C++20 port 2/14: compile the leaf modules as C++ (#3066)

* Make headers and leaf modules compile as C++

Wrap the declarations of every project header in extern "C" (after the
system includes, which must keep C++ linkage), so converted modules and
the remaining C files agree on linkage.

In the leaf modules, cast allocator and memchr results explicitly,
rename identifiers called new, replace the getpwnam_r VLA with the
fixed 16 KiB buffer the loop already capped itself at, and make the
rlimit initialiser conversion explicit. All of this is still valid C.

* Compile the leaf modules as C++

Rename base64, json, ipset, process, ppbloom, rule, ssurl and cache from
.c to .cpp without touching their contents, and update the CMake source
lists, debian/copyright and the docs.

Ported code keeps -Wall; -Wextra is now opt-in through
ss_strict_warnings() for code written as C++ (the core tests).
check_no_heap.py gains a ratchet baseline for the converted modules,
which still allocate the way the C code did. A new check_cxx_runtime
test verifies with nm that the programs and libshadowsocks-c.a still
need no C++ runtime library, so C consumers are unaffected.

* Fix the Windows branches of process.cpp for C++

Cast allocator results and the thread argument explicitly and
value-initialise JOBOBJECT_EXTENDED_LIMIT_INFORMATION with {}. Found by
the zig x86_64-windows-gnu cross build.

* Keep clang-tidy clean for the converted modules

Once the C headers are included from C++ translation units,
bugprone-dynamic-static-initializers reports each extern variable
declaration in them; none is defined in a header, so disable the check.
Mark the two bounded memchr searches in ssurl.cpp, which
bugprone-not-null-terminated-result misreads as string copies.

* check_cxx_runtime: ignore glibc symbol versions

nm on glibc prints __cxa_atexit@GLIBC_2.2.5, which the allowlist for the
libc-provided __cxa_atexit/__cxa_finalize did not match.

* Keep GCC's C++-only warnings off for modules converted from C

GCC's C++ -Wall includes -Wsign-compare and -Wclass-memaccess, which C's
-Wall does not, so the converted modules failed -Werror on GCC (Linux,
UCRT64) although nothing in them changed. They keep the warning set they
were written against; code under ss_strict_warnings() re-enables both.
This commit is contained in:
Max Lv authored and GitHub committed 2026-10-15 09:48:18 +08:00
1 parent bcb3731968
commit 384810efce
49 files changed
+476 -89

No files matched your search

+4 -1
View File
@@ -12,7 +12,9 @@
# reserved-identifier: the codebase uses _prefixed names and vendored
# uthash.h/generated config.h trip them ~600 times) or produce false
# positives with the event callback style (casting-through-void,
# multi-level-implicit-pointer-conversion).
# multi-level-implicit-pointer-conversion). dynamic-static-initializers
# fires on every extern variable declaration in the C headers once they are
# included from C++; none of them is defined or initialised in a header.
Checks: >
clang-analyzer-*,
bugprone-*,
@@ -20,6 +22,7 @@ Checks: >
-bugprone-assignment-in-if-condition,
-bugprone-branch-clone,
-bugprone-casting-through-void,
-bugprone-dynamic-static-initializers,
-bugprone-easily-swappable-parameters,
-bugprone-inc-dec-in-conditions,
-bugprone-implicit-widening-of-multiplication-result,
+5 -5
View File
@@ -103,9 +103,9 @@ 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.c` - JSON config file parsing
- `jconf.c` / `json.cpp` - JSON config file parsing
- `netutils.c` - network address utilities
- `cache.c` - uthash-based connection cache (UDP relay, AEAD-2022 tables)
- `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
@@ -115,11 +115,11 @@ A library `libshadowsocks-c` (legacy names `libshadowsocks-libev.*` are kept) is
- `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`
- `ppbloom.c` - ping-pong bloom filter for salt replay detection (`third_party/bloom`)
- `ppbloom.cpp` - ping-pong bloom filter for salt replay detection (`third_party/bloom`)
**ACL:** `acl.c` / `rule.c` / `ipset.c` - IP prefix sets and PCRE2/literal domain rules.
**ACL:** `acl.c` / `rule.cpp` / `ipset.cpp` - IP prefix sets and PCRE2/literal domain rules.
**Plugins:** `plugin.c` / `process.c` - SIP003 plugin subprocess management.
**Plugins:** `plugin.c` / `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`.
+18 -2
View File
@@ -26,9 +26,16 @@ function(ss_project_options target)
else()
target_compile_options(${target} PRIVATE -Wall -Wno-deprecated-declarations -fno-strict-aliasing)
# C++ sources: no exceptions or RTTI, and no locks around function
# statics (the event loop is single-threaded).
# statics (the event loop is single-threaded). New C++ code also opts
# into -Wextra through ss_strict_warnings(); modules ported from C get
# it when they are rewritten.
target_compile_options(${target} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:-Wextra -fno-exceptions -fno-rtti -fno-threadsafe-statics>)
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -fno-threadsafe-statics>)
# GCC's C++ -Wall adds -Wsign-compare and -Wclass-memaccess, which C's
# -Wall does not have. Modules converted from C keep the warning set
# they were written against; ss_strict_warnings() turns both back on.
target_compile_options(${target} PRIVATE
$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wno-sign-compare -Wno-class-memaccess>)
if(SS_WARNINGS_AS_ERRORS)
target_compile_options(${target} PRIVATE -Werror)
endif()
@@ -54,3 +61,12 @@ function(ss_project_options target)
target_link_options(${target} PRIVATE --coverage)
endif()
endfunction()
# Extra warnings for code written as C++ from the start (src/core and its
# tests).
function(ss_strict_warnings target)
if(NOT MSVC)
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wextra>
$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wsign-compare -Wclass-memaccess>)
endif()
endfunction()
+3 -3
View File
@@ -41,11 +41,11 @@ Files: scripts/build_deb.sh
Copyright: 2018 Roger Shimizu <rosh@debian.org>
License: GPL-3+
Files: src/base64.c src/base64.h
Files: src/base64.cpp src/base64.h
Copyright: 2006 Ryan Martell <rdm4@martellventures.com>
License: LGPL-2.1+
Files: src/json.c src/json.h
Files: src/json.cpp src/json.h
Copyright: 2012-2014, James McLaughlin et al.
License: BSD-2-clause
@@ -53,7 +53,7 @@ Files: src/resolv.c src/resolv.h
Copyright: 2011-2014, Dustin Lundquist <dustin@null-ptr.net>
License: BSD-2-clause
Files: src/rule.c src/rule.h
Files: src/rule.cpp src/rule.h
Copyright: 2011-2012, Dustin Lundquist <dustin@null-ptr.net>
2011, Manuel Kasper <mk@neon1.net>
License: BSD-2-clause
+1 -1
View File
@@ -43,7 +43,7 @@ All binaries are still built from the C sources.
| `ref.hpp` | `RefCounted<T>`/`RefPtr<T>`, intrusive shared ownership for the few genuinely shared objects (AEAD-2022 UDP sessions). Used instead of `std::shared_ptr` because its control block cannot be pooled portably. |
| `buffer.hpp` | `FixedBuffer<N>`: inline bytes with `std::span` views; replaces `buffer_t`. |
| `arena.hpp` | `MonotonicArena` for configuration data that lives as long as the process. |
| `fixed_map.hpp` | `FixedHashMap` (open addressing, backward-shift deletion) and `FixedLru`; replace uthash and `cache.c`. |
| `fixed_map.hpp` | `FixedHashMap` (open addressing, backward-shift deletion) and `FixedLru`; replace uthash and `cache.cpp`. |
| `intrusive_list.hpp` | `IntrusiveList`/`ListNode`; replaces `ss_list`. Nodes unlink themselves when destroyed. |
| `fixed_heap.hpp` | Bounded size-class allocator to hand to libuv, c-ares and Mbed TLS through their allocator hooks. |
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-or-later
"""Fail if programs or libraries need the C++ runtime library.
The C++ core is built without exceptions or RTTI and uses only header-only
parts of the standard library, so the programs and libshadowsocks-c stay
consumable from plain C: a C program linking libshadowsocks-c.a must not need
libstdc++ or libc++. This script lists the undefined symbols of each file with
nm and rejects anything served by the C++ runtime (operator new/delete,
exception and RTTI support, std:: functions).
Usage: check_cxx_runtime.py [--nm NM] FILE...
"""
import argparse
import re
import shutil
import subprocess
import sys
# Itanium-ABI names (with or without the Mach-O leading underscore) that only
# the C++ runtime defines.
RUNTIME = re.compile(
r"^_?(?:"
r"_Zn[wa]|_Zd[la]|" # operator new / delete
r"_ZSt|_ZNSt|_ZNKSt|" # std:: functions and members
r"_ZTI|_ZTS|_ZTV|" # typeinfo / vtables (RTTI, classes from the runtime)
r"__cxa_(?!atexit$|finalize$|thread_atexit_impl$)|" # exception/guard support; libc owns these three
r"__gxx_personality|_Unwind_|__dynamic_cast"
r")"
)
def undefined_symbols(nm, path):
result = subprocess.run([nm, "-u", path], capture_output=True, text=True)
if result.returncode != 0:
raise SystemExit(f"{nm} failed on {path}: {result.stderr.strip()}")
symbols = set()
for line in result.stdout.splitlines():
line = line.strip()
if not line or line.endswith(":"):
continue # archive member headers
# glibc nm prints versioned names (__cxa_atexit@GLIBC_2.2.5).
symbols.add(line.split()[-1].split("@")[0])
return symbols
def main():
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--nm", default=shutil.which("nm") or "nm")
parser.add_argument("files", nargs="+")
args = parser.parse_args()
failed = False
for path in args.files:
bad = sorted(s for s in undefined_symbols(args.nm, path) if RUNTIME.match(s))
if bad:
failed = True
print(f"{path}: needs the C++ runtime:")
for symbol in bad:
print(f" {symbol}")
else:
print(f"{path}: ok")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())
+44 -9
View File
@@ -14,7 +14,12 @@ A line that must allocate (a startup reservation) carries a justification:
void *base = std::calloc(1, size); // heap-ok: startup reservation
Usage: check_no_heap.py [--root DIR] [--self-test]
Modules converted mechanically from C still allocate the way the C code did
until they are rewritten. scripts/no_heap_baseline.txt lists them with their
current violation counts, and works as a ratchet: a file may not gain
violations, and when it loses some the baseline must be lowered to match.
Usage: check_no_heap.py [--root DIR] [--baseline FILE] [--self-test]
"""
import argparse
@@ -89,16 +94,42 @@ def check_text(text):
return problems
def check_tree(root):
def read_baseline(path):
baseline = {}
if path is None or not path.exists():
return baseline
for raw in path.read_text(encoding="utf-8").splitlines():
line = raw.split("#", 1)[0].strip()
if line:
name, count = line.split()
baseline[name] = int(count)
return baseline
def check_tree(root, baseline):
src = root / "src"
files = sorted(p for p in src.rglob("*") if p.suffix in (".cpp", ".hpp") and "blake3" not in p.parts)
failures = 0
ok = True
total = 0
for path in files:
for number, why, line in check_text(path.read_text(encoding="utf-8")):
print(f"{path.relative_to(root)}:{number}: {why}: {line}")
failures += 1
print(f"check_no_heap: {len(files)} C++ files, {failures} violation(s)")
return failures == 0
name = path.relative_to(root).as_posix()
problems = check_text(path.read_text(encoding="utf-8"))
allowed = baseline.pop(name, 0)
total += len(problems)
if len(problems) > allowed:
for number, why, line in problems:
print(f"{name}:{number}: {why}: {line}")
print(f"{name}: {len(problems)} violation(s), baseline allows {allowed}")
ok = False
elif len(problems) < allowed:
print(f"{name}: {len(problems)} violation(s), below the baseline of {allowed}; "
"lower it in scripts/no_heap_baseline.txt")
ok = False
for name in sorted(baseline):
print(f"{name}: listed in the baseline but not a C++ source; remove the entry")
ok = False
print(f"check_no_heap: {len(files)} C++ files, {total} baselined or new violation(s)")
return ok
def self_test():
@@ -144,11 +175,15 @@ def self_test():
def main():
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--root", type=pathlib.Path, default=pathlib.Path(__file__).resolve().parent.parent)
parser.add_argument("--baseline", type=pathlib.Path,
help="ratchet file (default: scripts/no_heap_baseline.txt under --root)")
parser.add_argument("--self-test", action="store_true", help="run the pattern self-test first")
args = parser.parse_args()
if args.self_test and not self_test():
return 1
return 0 if check_tree(args.root.resolve()) else 1
root = args.root.resolve()
baseline = read_baseline(args.baseline or root / "scripts" / "no_heap_baseline.txt")
return 0 if check_tree(root, baseline) else 1
if __name__ == "__main__":
+10
View File
@@ -0,0 +1,10 @@
# Heap-allocation ratchet for C++ sources converted mechanically from C.
# Format: <path> <violations>. 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/cache.cpp 3
src/ipset.cpp 3
src/json.cpp 2
src/process.cpp 26
src/rule.cpp 2
src/ssurl.cpp 3
+11 -11
View File
@@ -10,8 +10,8 @@ endif ()
set(SS_ACL_SOURCE
acl.c
ipset.c
rule.c
ipset.cpp
rule.cpp
)
set(SS_CRYPTO_SOURCE
@@ -19,7 +19,7 @@ set(SS_CRYPTO_SOURCE
aead.c
aead2022.c
aead2022_udp.c
base64.c
base64.cpp
)
# BLAKE3 (vendored) provides the key derivation for the 2022 ciphers. Only
@@ -43,16 +43,16 @@ if(SS_ENABLE_LEGACY)
list(APPEND SS_CRYPTO_SOURCE stream.c)
endif()
if(SS_ENABLE_PLUGINS)
set(SS_PLUGIN_SOURCE plugin.c process.c)
set(SS_PLUGIN_SOURCE plugin.c process.cpp)
else()
set(SS_PLUGIN_SOURCE plugin_disabled.c)
endif()
set(SS_SHARED_SOURCES
ppbloom.c
ppbloom.cpp
utils.c
jconf.c
json.c
json.cpp
netutils.c
)
if (MINGW)
@@ -62,10 +62,10 @@ endif ()
set(LIBSHADOWSOCKS_LIBEV_SOURCE
${SS_SHARED_SOURCES}
udprelay.c
cache.c
cache.cpp
local.c
resolv.c
ssurl.c
ssurl.cpp
${SS_CRYPTO_SOURCE}
${SS_PLUGIN_SOURCE}
${SS_ACL_SOURCE}
@@ -79,7 +79,7 @@ set(SS_LOCAL_SOURCE
set(SS_TUNNEL_SOURCE
${SS_SHARED_SOURCES}
udprelay.c
cache.c
cache.cpp
tunnel.c
${SS_CRYPTO_SOURCE}
${SS_PLUGIN_SOURCE}
@@ -88,7 +88,7 @@ set(SS_TUNNEL_SOURCE
set(SS_SERVER_SOURCE
${SS_SHARED_SOURCES}
udprelay.c
cache.c
cache.cpp
resolv.c
server.c
${SS_CRYPTO_SOURCE}
@@ -104,7 +104,7 @@ set(SS_MANAGER_SOURCE
set(SS_REDIR_SOURCE
${SS_SHARED_SOURCES}
udprelay.c
cache.c
cache.cpp
redir.c
${SS_CRYPTO_SOURCE}
${SS_PLUGIN_SOURCE}
+8
View File
@@ -23,6 +23,10 @@
#ifndef _ACL_H
#define _ACL_H
#ifdef __cplusplus
extern "C" {
#endif
#define BLACK_LIST 0
#define WHITE_LIST 1
@@ -37,4 +41,8 @@ int get_acl_mode(void);
int outbound_block_match_host(const char *host);
#ifdef __cplusplus
}
#endif
#endif // _ACL_H
+8
View File
@@ -25,6 +25,10 @@
#include "crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
// currently, XCHACHA20POLY1305IETF is not released yet
// XCHACHA20POLY1305 is removed in upstream
#ifdef FS_HAVE_XCHACHA20IETF
@@ -52,4 +56,8 @@ int aead_2022_encrypt_udp(buffer_t *, cipher_t *, size_t, void **);
int aead_2022_decrypt_udp(buffer_t *, cipher_t *, size_t, void **);
void aead_2022_udp_session_release(void *);
#ifdef __cplusplus
}
#endif
#endif // _AEAD_H
+8
View File
@@ -25,6 +25,10 @@
#include "crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
/* AEAD method identifiers (indexes into the supported_aead_ciphers tables) */
#define AES128GCM 0
#define AES192GCM 1
@@ -73,4 +77,8 @@ int ss2022_tcp_encrypt(buffer_t *plaintext, cipher_ctx_t *cipher_ctx,
int ss2022_tcp_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx,
size_t capacity);
#ifdef __cplusplus
}
#endif
#endif // _AEAD_INTERNAL_H
View File
File renamed without changes.
+8
View File
@@ -23,6 +23,10 @@
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Decode a base64-encoded string.
*
@@ -51,4 +55,8 @@ char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size);
*/
#define BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
#ifdef __cplusplus
}
#endif
#endif /* BASE64_H */
+11 -11
View File
@@ -50,20 +50,20 @@ int
cache_create(struct cache **dst, const size_t capacity,
void (*free_cb)(void *key, void *element))
{
struct cache *new = NULL;
struct cache *created = NULL;
if (!dst) {
return EINVAL;
}
if ((new = malloc(sizeof(*new))) == NULL) {
if ((created = (struct cache *)malloc(sizeof(*created))) == NULL) {
return ENOMEM;
}
new->max_entries = capacity;
new->entries = NULL;
new->free_cb = free_cb;
*dst = new;
created->max_entries = capacity;
created->entries = NULL;
created->free_cb = free_cb;
*dst = created;
return 0;
}
@@ -212,7 +212,7 @@ int
cache_lookup(struct cache *cache, char *key, size_t key_len, void *result)
{
struct cache_entry *tmp = NULL;
char **dirty_hack = result;
void **out = (void **)result;
if (!cache || !key || !result) {
return EINVAL;
@@ -224,9 +224,9 @@ cache_lookup(struct cache *cache, char *key, size_t key_len, void *result)
tmp->ts = ss_monotonic_time();
// NOLINTNEXTLINE(clang-analyzer-core.DivideZero): uthash bucket count is never zero
HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp);
*dirty_hack = tmp->data;
*out = tmp->data;
} else {
*dirty_hack = result = NULL;
*out = NULL;
}
return 0;
@@ -279,11 +279,11 @@ cache_insert(struct cache *cache, char *key, size_t key_len, void *data)
return EINVAL;
}
if ((entry = malloc(sizeof(*entry))) == NULL) {
if ((entry = (struct cache_entry *)malloc(sizeof(*entry))) == NULL) {
return ENOMEM;
}
entry->key = ss_malloc(key_len + 1);
entry->key = (char *)ss_malloc(key_len + 1);
memcpy(entry->key, key, key_len);
entry->key[key_len] = 0;
+8
View File
@@ -30,6 +30,10 @@
#include "uthash.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A cache entry
*/
@@ -58,4 +62,8 @@ int cache_insert(struct cache *cache, char *key, size_t key_len, void *data);
int cache_remove(struct cache *cache, char *key, size_t key_len);
int cache_key_exist(struct cache *cache, char *key, size_t key_len);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -32,6 +32,10 @@
#include "crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
int init_udprelay(const char *server_host, const char *server_port,
#ifdef MODULE_LOCAL
const struct sockaddr *remote_addr, const int remote_addr_len,
@@ -83,4 +87,8 @@ enum {
GETOPT_VAL_IPV4_FIRST
};
#ifdef __cplusplus
}
#endif
#endif // _COMMON_H
+8
View File
@@ -6,6 +6,10 @@
#include <stdint.h>
#include "platform.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ss_container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
struct ss_list_item {
@@ -71,4 +75,8 @@ ss_ip_init(struct ss_ip *ip, const char *text)
ip->version = 0;
return -1;
}
#ifdef __cplusplus
}
#endif
#endif
+2 -2
View File
@@ -2,7 +2,7 @@
#ifndef SS_CORE_FIXED_MAP_HPP
#define SS_CORE_FIXED_MAP_HPP
// Fixed-capacity associative containers. Replace uthash (cache.c,
// Fixed-capacity associative containers. Replace uthash (cache.cpp,
// ss_event.c, manager.c) without any per-entry allocation.
//
// FixedHashMap<K, V>
@@ -15,7 +15,7 @@
// FixedLru<K, V>
// Map plus recency order. Values live in a slab and never move, so the
// pointer returned by insert() or find() stays valid until that entry
// is erased or evicted. Replaces the pseudo-LRU in cache.c.
// is erased or evicted. Replaces the pseudo-LRU in cache.cpp.
//
// Keys from the network (UDP peer addresses, session IDs) are hashed with a
// per-table seed. Seed it from a CSPRNG in production code so a peer cannot
+8
View File
@@ -42,6 +42,10 @@ typedef crypto_aead_aes256gcm_state aes256gcm_ctx;
/* Definitions for mbedTLS */
#include <mbedtls/cipher.h>
#include <mbedtls/md.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef mbedtls_cipher_info_t cipher_kt_t;
typedef mbedtls_cipher_context_t cipher_evp_t;
typedef mbedtls_md_info_t digest_type_t;
@@ -206,4 +210,8 @@ extern struct cache *nonce_cache;
extern const char *supported_stream_ciphers[];
extern const char *supported_aead_ciphers[];
#ifdef __cplusplus
}
#endif
#endif // _CRYPTO_H
+1 -1
View File
@@ -14,7 +14,7 @@ struct ss_ipset_node {
static struct ss_ipset_node *
node_new(bool full)
{
struct ss_ipset_node *node = ss_malloc(sizeof(*node));
struct ss_ipset_node *node = (struct ss_ipset_node *)ss_malloc(sizeof(*node));
node->child[0] = node->child[1] = NULL;
node->full = full;
return node;
+8
View File
@@ -4,6 +4,10 @@
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ss_ipset_node;
struct ss_ipset {
struct ss_ipset_node *root;
@@ -15,4 +19,8 @@ void ss_ipset_clear(struct ss_ipset *set);
void ss_ipset_assign(struct ss_ipset *set, const uint8_t *address,
unsigned width, unsigned prefix, bool present);
bool ss_ipset_contains(const struct ss_ipset *set, const uint8_t *address, unsigned width);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -22,6 +22,10 @@
#ifndef _JCONF_H
#define _JCONF_H
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_PORT_NUM 1024
#define MAX_REMOTE_NUM 10
#define MAX_DSCP_NUM 64
@@ -99,4 +103,8 @@ void free_addr(ss_addr_t *addr);
int parse_server_endpoint(const char *str, ss_addr_t *addr);
int complete_server_ports(ss_addr_t *addr, int count, const char *fallback, int plugin);
#ifdef __cplusplus
}
#endif
#endif // _JCONF_H
View File
File renamed without changes.
+8
View File
@@ -36,6 +36,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct listen_ctx {
ss_io io;
char *iface;
@@ -100,4 +104,8 @@ typedef struct remote {
struct sockaddr_storage addr;
} remote_t;
#ifdef __cplusplus
}
#endif
#endif // _LOCAL_H
+8
View File
@@ -33,6 +33,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
struct manager_ctx {
ss_io io;
int fd;
@@ -75,4 +79,8 @@ struct server {
uint64_t traffic;
};
#ifdef __cplusplus
}
#endif
#endif // _MANAGER_H
+8
View File
@@ -39,6 +39,10 @@
#include <netdb.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Hard coded defines for TCP fast open on Android */
#ifdef __ANDROID__
#ifndef TCP_FASTOPEN
@@ -127,4 +131,8 @@ int validate_hostname(const char *hostname, const int hostname_len);
int is_ipv6only(ss_addr_t *servers, size_t server_num, int ipv6first);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -17,6 +17,10 @@ typedef SOCKET ss_socket_t;
typedef int ss_socket_t;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Socket errors are separate from CRT errno on Windows. Return normalized
* errno constants for portable branching without redefining libc names. */
static inline int
@@ -117,4 +121,8 @@ ss_monotonic_time(void)
return (double)value.tv_sec + (double)value.tv_nsec / 1000000000.0;
#endif
}
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -23,6 +23,10 @@
#ifndef _PLUGIN_H
#define _PLUGIN_H
#ifdef __cplusplus
extern "C" {
#endif
#define PLUGIN_EXIT_ERROR -2
#define PLUGIN_EXIT_NORMAL -1
#define PLUGIN_RUNNING 0
@@ -77,4 +81,8 @@ uint16_t get_local_port();
void stop_plugin();
int is_plugin_running();
#ifdef __cplusplus
}
#endif
#endif // _PLUGIN_H
View File
File renamed without changes.
+8
View File
@@ -23,9 +23,17 @@
#ifndef _PPBLOOM_
#define _PPBLOOM_
#ifdef __cplusplus
extern "C" {
#endif
int ppbloom_init(int entries, double error);
int ppbloom_check(const void *buffer, int len);
int ppbloom_add(const void *buffer, int len);
void ppbloom_free(void);
#ifdef __cplusplus
}
#endif
#endif
+14 -14
View File
@@ -32,7 +32,7 @@ static char *
copy_string(const char *text)
{
size_t size = strlen(text) + 1;
char *copy = ss_malloc(size);
char *copy = (char *)ss_malloc(size);
memcpy(copy, text, size);
return copy;
}
@@ -40,7 +40,7 @@ copy_string(const char *text)
struct ss_process *
ss_process_new(const char *program)
{
struct ss_process *process = ss_malloc(sizeof(*process));
struct ss_process *process = (struct ss_process *)ss_malloc(sizeof(*process));
memset(process, 0, sizeof(*process));
process->program = copy_string(program);
return process;
@@ -49,7 +49,7 @@ ss_process_new(const char *program)
void
ss_process_arg(struct ss_process *process, const char *argument)
{
process->argv = ss_realloc(process->argv, (process->argc + 2) * sizeof(char *));
process->argv = (char **)ss_realloc(process->argv, (process->argc + 2) * sizeof(char *));
process->argv[process->argc++] = copy_string(argument);
process->argv[process->argc] = NULL;
}
@@ -58,9 +58,9 @@ void
ss_process_env(struct ss_process *process, const char *name, const char *value)
{
size_t size = strlen(name) + strlen(value) + 2;
char *entry = ss_malloc(size);
char *entry = (char *)ss_malloc(size);
snprintf(entry, size, "%s=%s", name, value);
process->env = ss_realloc(process->env, (process->envc + 2) * sizeof(char *));
process->env = (char **)ss_realloc(process->env, (process->envc + 2) * sizeof(char *));
process->env[process->envc++] = entry;
process->env[process->envc] = NULL;
}
@@ -90,7 +90,7 @@ ss_process_start(struct ss_process *process, uint16_t control_port)
while (environ[count] != NULL) {
count++;
}
char **env = ss_malloc((count + process->envc + 1) * sizeof(char *));
char **env = (char **)ss_malloc((count + process->envc + 1) * sizeof(char *));
for (size_t i = 0; i < count; i++) {
if (!overridden(process, environ[i])) {
env[used++] = environ[i];
@@ -164,7 +164,7 @@ wide_string(const char *text)
{
int count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, -1, NULL, 0);
if (count == 0) return NULL;
wchar_t *wide = ss_malloc((size_t)count * sizeof(wchar_t));
wchar_t *wide = (wchar_t *)ss_malloc((size_t)count * sizeof(wchar_t));
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, -1, wide, count)) {
free(wide);
return NULL;
@@ -175,7 +175,7 @@ wide_string(const char *text)
static DWORD WINAPI
monitor_process(void *argument)
{
struct ss_process *process = argument;
struct ss_process *process = (struct ss_process *)argument;
WaitForSingleObject(process->child, INFINITE);
if (process->control_port != 0) {
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -207,11 +207,11 @@ sort_environment(wchar_t *env)
count++;
length += wcslen(entry) + 1;
}
wchar_t **entries = ss_malloc((count + 1) * sizeof(*entries));
wchar_t **entries = (wchar_t **)ss_malloc((count + 1) * sizeof(*entries));
size_t index = 0;
for (wchar_t *entry = env; *entry; entry += wcslen(entry) + 1) entries[index++] = entry;
qsort(entries, count, sizeof(*entries), compare_environment);
wchar_t *sorted = ss_malloc((length + 1) * sizeof(*sorted)), *out = sorted;
wchar_t *sorted = (wchar_t *)ss_malloc((length + 1) * sizeof(*sorted)), *out = sorted;
for (size_t i = 0; i < count; i++) {
size_t size = wcslen(entries[i]) + 1;
memcpy(out, entries[i], size * sizeof(*out));
@@ -231,7 +231,7 @@ ss_process_start(struct ss_process *process, uint16_t control_port)
* Double backslashes before a quote or the closing quote. */
size_t capacity = 1;
for (size_t i = 0; i < process->argc; i++) capacity += 2 * strlen(process->argv[i]) + 4;
char *command = ss_malloc(capacity), *out = command;
char *command = (char *)ss_malloc(capacity), *out = command;
for (size_t i = 0; i < process->argc; i++) {
if (i != 0) *out++ = ' ';
*out++ = '"';
@@ -254,7 +254,7 @@ ss_process_start(struct ss_process *process, uint16_t control_port)
wchar_t *inherited = GetEnvironmentStringsW();
if (inherited == NULL) { free(wide_command); return -1; }
wchar_t **overrides = ss_malloc((process->envc + 1) * sizeof(wchar_t *));
wchar_t **overrides = (wchar_t **)ss_malloc((process->envc + 1) * sizeof(wchar_t *));
size_t total = 2;
for (const wchar_t *entry = inherited; *entry; entry += wcslen(entry) + 1) total += wcslen(entry) + 1;
for (size_t i = 0; i < process->envc; i++) {
@@ -266,7 +266,7 @@ ss_process_start(struct ss_process *process, uint16_t control_port)
}
total += wcslen(overrides[i]) + 1;
}
wchar_t *env = ss_malloc(total * sizeof(wchar_t)), *dest = env;
wchar_t *env = (wchar_t *)ss_malloc(total * sizeof(wchar_t)), *dest = env;
for (const wchar_t *entry = inherited; *entry; entry += wcslen(entry) + 1) {
const wchar_t *equals = wcschr(entry, L'=');
bool replace = false;
@@ -292,7 +292,7 @@ ss_process_start(struct ss_process *process, uint16_t control_port)
PROCESS_INFORMATION child = {0};
startup.cb = sizeof(startup);
process->job = CreateJobObjectW(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits = {0};
JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits = {};
limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
BOOL ok = process->job != NULL && SetInformationJobObject(process->job,
JobObjectExtendedLimitInformation, &limits, sizeof(limits));
+8
View File
@@ -27,6 +27,10 @@
#include "crypto.h"
#include "jconf.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct listen_ctx {
ss_io io;
int remote_num;
@@ -75,4 +79,8 @@ typedef struct remote {
struct sockaddr *addr;
} remote_t;
#ifdef __cplusplus
}
#endif
#endif // _REDIR_H
+8
View File
@@ -35,6 +35,10 @@
#include <sys/socket.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct ss_loop;
struct resolv_query;
@@ -44,4 +48,8 @@ void resolv_start(const char *hostname, uint16_t port,
void (*free_cb)(void *), void *data);
void resolv_shutdown(struct ss_loop *);
#ifdef __cplusplus
}
#endif
#endif
+1 -1
View File
@@ -40,7 +40,7 @@ new_rule()
{
rule_t *rule;
rule = calloc(1, sizeof(rule_t));
rule = (rule_t *)calloc(1, sizeof(rule_t));
if (rule == NULL) {
ERROR("malloc");
return NULL;
+8
View File
@@ -38,6 +38,10 @@
#include <pcre2.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rule {
struct ss_list_item entries;
@@ -61,4 +65,8 @@ void remove_rule(rule_t *);
rule_t *new_rule();
int accept_rule_arg(rule_t *, const char *);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -38,6 +38,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct listen_ctx {
ss_io io;
int fd;
@@ -114,4 +118,8 @@ typedef struct remote {
struct server *server;
} remote_t;
#ifdef __cplusplus
}
#endif
#endif // _SERVER_H
+8
View File
@@ -23,6 +23,10 @@
#ifndef _SOCKS5_H
#define _SOCKS5_H
#ifdef __cplusplus
extern "C" {
#endif
#define SVERSION 0x05
#define METHOD_NOAUTH 0x00
#define METHOD_UNACCEPTABLE 0xff
@@ -72,4 +76,8 @@ struct socks5_response {
unsigned char atyp;
} __attribute__((packed, aligned(1)));
#ifdef __cplusplus
}
#endif
#endif // _SOCKS5_H
+8
View File
@@ -3,6 +3,10 @@
#ifndef SS_EVENT_H
#define SS_EVENT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Keep platform headers private: Linux TCP headers differ from libc headers. */
struct uv_loop_s;
struct ss_loop;
@@ -55,4 +59,8 @@ 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 *);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -3,6 +3,10 @@
#define SS_PROCESS_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ss_process;
struct ss_process *ss_process_new(const char *program);
void ss_process_arg(struct ss_process *process, const char *argument);
@@ -10,4 +14,8 @@ void ss_process_env(struct ss_process *process, const char *name, const char *va
int ss_process_start(struct ss_process *process, uint16_t control_port);
bool ss_process_running(struct ss_process *process);
void ss_process_free(struct ss_process *process);
#ifdef __cplusplus
}
#endif
#endif
+8
View File
@@ -44,6 +44,10 @@
#include <ws2tcpip.h>
#include <mswsock.h>
#ifdef __cplusplus
extern "C" {
#endif
// Check if ConnectEx supported in header
#ifdef WSAID_CONNECTEX
// Hardcode TCP fast open option
@@ -80,6 +84,10 @@ LPFN_CONNECTEX winsock_getconnectex(void);
int winsock_dummybind(SOCKET fd, struct sockaddr *sa);
#endif
#ifdef __cplusplus
}
#endif
#endif // __MINGW32__
#endif // SS_WINSOCK_COMPAT_H
+10 -8
View File
@@ -50,7 +50,7 @@ find_last(const char *s, size_t len, char c)
static char *
str_ndup(const char *s, size_t n)
{
char *out = ss_malloc(n + 1);
char *out = (char *)ss_malloc(n + 1);
memcpy(out, s, n);
out[n] = '\0';
@@ -73,7 +73,7 @@ hex_value(char c)
static char *
percent_decode(const char *s, size_t len)
{
char *out = ss_malloc(len + 1);
char *out = (char *)ss_malloc(len + 1);
size_t o = 0;
for (size_t i = 0; i < len; i++) {
@@ -106,7 +106,7 @@ base64_dup(const char *s, size_t len)
char *in = str_ndup(s, len);
/* decoded output is always shorter than the encoded input */
uint8_t *out = ss_malloc(len + 1);
uint8_t *out = (uint8_t *)ss_malloc(len + 1);
int out_len = base64_decode(out, in, (int)len);
ss_free(in);
@@ -131,7 +131,7 @@ split_host_port(const char *s, size_t len, ss_url_t *url)
return -1;
if (s[0] == '[') {
const char *close = memchr(s, ']', len);
const char *close = (const char *)memchr(s, ']', len);
if (close == NULL)
return -1;
@@ -186,9 +186,9 @@ parse_query(const char *s, size_t len, ss_url_t *url)
const char *end = s + len;
while (s < end) {
const char *amp = memchr(s, '&', (size_t)(end - s));
const char *amp = (const char *)memchr(s, '&', (size_t)(end - s));
const char *pair_end = amp ? amp : end;
const char *eq = memchr(s, '=', (size_t)(pair_end - s));
const char *eq = (const char *)memchr(s, '=', (size_t)(pair_end - s));
if (eq != NULL) {
size_t name_len = (size_t)(eq - s);
@@ -244,13 +244,15 @@ ss_url_parse(const char *uri, ss_url_t *url)
return -1;
/* The fragment is a human-readable tag and is not part of the config. */
const char *hash = memchr(body, '#', body_len);
// NOLINTNEXTLINE(bugprone-not-null-terminated-result): memchr searches a bounded span, no string is produced
const char *hash = (const char *)memchr(body, '#', body_len);
if (hash != NULL) {
url->tag = percent_decode(hash + 1, body_len - (size_t)(hash - body) - 1);
body_len = (size_t)(hash - body);
}
const char *query = memchr(body, '?', body_len);
// NOLINTNEXTLINE(bugprone-not-null-terminated-result): memchr searches a bounded span, no string is produced
const char *query = (const char *)memchr(body, '?', body_len);
size_t head_len = query ? (size_t)(query - body) : body_len;
/*
+8
View File
@@ -23,6 +23,10 @@
#ifndef _SSURL_H
#define _SSURL_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* A parsed ss:// URI. Every field is heap-allocated and owned by the
* struct; release them all with ss_url_free(). Fields that the URI did not
@@ -55,4 +59,8 @@ int ss_url_parse(const char *uri, ss_url_t *url);
/* Free every field and zero the struct. Safe on a zeroed struct. */
void ss_url_free(ss_url_t *url);
#ifdef __cplusplus
}
#endif
#endif // _SSURL_H
+8
View File
@@ -41,6 +41,10 @@
#include "crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
int stream_encrypt_all(buffer_t *, cipher_t *, size_t);
int stream_decrypt_all(buffer_t *, cipher_t *, size_t);
int stream_encrypt(buffer_t *, cipher_ctx_t *, size_t);
@@ -51,4 +55,8 @@ void stream_ctx_release(cipher_ctx_t *);
cipher_t *stream_init(const char *pass, const char *key, const char *method);
#ifdef __cplusplus
}
#endif
#endif // _STREAM_H
+8
View File
@@ -34,6 +34,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct listen_ctx {
ss_io io;
ss_addr_t tunnel_addr;
@@ -84,4 +88,8 @@ typedef struct remote {
uint32_t counter;
} remote_t;
#ifdef __cplusplus
}
#endif
#endif // _TUNNEL_H
+8
View File
@@ -38,6 +38,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_UDP_PACKET_SIZE (65507)
#define PACKET_HEADER_SIZE (1 + 28 + 2 + 64)
@@ -92,4 +96,8 @@ typedef struct remote_ctx {
struct server_ctx *server_ctx;
} remote_ctx_t;
#ifdef __cplusplus
}
#endif
#endif // _UDPRELAY_H
+8 -6
View File
@@ -164,8 +164,10 @@ run_as(const char *user)
size_t buflen;
int err;
/* The loop below gives up beyond 16 KiB, so one fixed buffer covers
* every attempt. */
char buf[16 * 1024];
for (buflen = 128;; buflen *= 2) {
char buf[buflen]; /* variable length array */
/* Note that we use getpwnam_r() instead of getpwnam(),
* which returns its result in a statically allocated buffer and
@@ -256,7 +258,7 @@ ss_strndup(const char *s, size_t n)
len++;
}
ret = ss_malloc(len + 1);
ret = (char *)ss_malloc(len + 1);
memcpy(ret, s, len);
ret[len] = '\0';
return ret;
@@ -302,13 +304,13 @@ ss_aligned_malloc(size_t size)
void *
ss_realloc(void *ptr, size_t new_size)
{
void *new = realloc(ptr, new_size);
if (new == NULL) {
void *resized = realloc(ptr, new_size);
if (resized == NULL) {
free(ptr);
ptr = NULL;
exit(EXIT_FAILURE);
}
return new;
return resized;
}
int
@@ -803,7 +805,7 @@ daemonize(const char *path)
int
set_nofile(int nofile)
{
struct rlimit limit = { nofile, nofile }; /* set both soft and hard limit */
struct rlimit limit = { (rlim_t)nofile, (rlim_t)nofile }; /* set both soft and hard limit */
if (nofile <= 0) {
FATAL("nofile must be greater than 0\n");
+8
View File
@@ -30,6 +30,10 @@
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PORTSTRLEN 16
#define SS_ADDRSTRLEN (INET6_ADDRSTRLEN + PORTSTRLEN + 1)
@@ -252,4 +256,8 @@ char *get_default_conf(void);
uint16_t load16_be(const void *s);
int get_mptcp(int enable);
#ifdef __cplusplus
}
#endif
#endif // _UTILS_H
+34 -14
View File
@@ -60,6 +60,7 @@ endfunction()
# C++ core (src/core): header-only ownership and allocation primitives.
foreach(core_test result pool buffer arena fixed_map ownership)
ss_add_test(test_core_${core_test} "test_core_${core_test}.cpp" "")
ss_strict_warnings(test_core_${core_test})
endforeach()
# C++ sources under src/ must not allocate on the heap (see the script).
@@ -68,11 +69,30 @@ if(Python3_Interpreter_FOUND)
add_test(NAME check_no_heap
COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/check_no_heap.py --self-test)
set_tests_properties(check_no_heap PROPERTIES LABELS "unit")
# The programs and the static library must stay usable without a C++
# runtime library (see docs/cpp-core.md). Sanitizer runtimes bring their
# own C++ symbols, so skip the check there.
set(SS_RUNTIME_CHECKED)
foreach(target ss-local ss-server ss-tunnel ss-redir ss-manager shadowsocks-c-static)
if(TARGET ${target})
get_target_property(excluded ${target} EXCLUDE_FROM_ALL)
if(NOT excluded)
list(APPEND SS_RUNTIME_CHECKED $<TARGET_FILE:${target}>)
endif()
endif()
endforeach()
if(SS_RUNTIME_CHECKED AND CMAKE_NM AND NOT ENABLE_SANITIZERS)
add_test(NAME check_cxx_runtime
COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/check_cxx_runtime.py
--nm ${CMAKE_NM} ${SS_RUNTIME_CHECKED})
set_tests_properties(check_cxx_runtime PROPERTIES LABELS "unit")
endif()
endif()
# test_base64 - no external deps
ss_add_test(test_base64
"test_base64.c;${PROJECT_SOURCE_DIR}/src/base64.c"
"test_base64.c;${PROJECT_SOURCE_DIR}/src/base64.cpp"
"")
# test_utils - needs sodium (for ss_malloc -> uses sodium in utils.c)
@@ -82,12 +102,12 @@ ss_add_test(test_utils
# test_json - standalone json parser
ss_add_test(test_json
"test_json.c;${PROJECT_SOURCE_DIR}/src/json.c"
"test_json.c;${PROJECT_SOURCE_DIR}/src/json.cpp"
"${SS_MATH_LIBRARY}")
# test_ssurl - ss:// URI parsing (SIP002 and legacy)
ss_add_test(test_ssurl
"test_ssurl.c;${PROJECT_SOURCE_DIR}/src/ssurl.c;${PROJECT_SOURCE_DIR}/src/base64.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_ssurl.c;${PROJECT_SOURCE_DIR}/src/ssurl.cpp;${PROJECT_SOURCE_DIR}/src/base64.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"ss_sodium")
# test_netutils - address parsing and resolver integration
@@ -102,14 +122,14 @@ ss_add_test(test_netutils
# test_cache - expiration uses a platform monotonic clock
ss_add_test(test_cache
"test_cache.c;${PROJECT_SOURCE_DIR}/src/cache.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_cache.c;${PROJECT_SOURCE_DIR}/src/cache.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"ss_sodium")
# test_ppbloom - needs bloom
set(TEST_PPBLOOM_LIBS "")
list(APPEND TEST_PPBLOOM_LIBS bloom)
ss_add_test(test_ppbloom
"test_ppbloom.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_ppbloom.c;${PROJECT_SOURCE_DIR}/src/ppbloom.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"${TEST_PPBLOOM_LIBS};ss_sodium;${SS_MATH_LIBRARY}")
if(SS_ENABLE_REGEX)
@@ -119,13 +139,13 @@ set(TEST_RULE_LIBS
ss_sodium
)
ss_add_test(test_rule
"test_rule.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_rule.c;${PROJECT_SOURCE_DIR}/src/rule.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"${TEST_RULE_LIBS}")
# 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.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"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_LIBS}")
endif()
@@ -137,7 +157,7 @@ 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.c;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/netutils.c"
"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_LIBS};${SS_MATH_LIBRARY}")
# Crypto sources shared by the tests that link the crypto layer. The AEAD-2022
@@ -148,9 +168,9 @@ set(SS_CRYPTO_TEST_SOURCES
${PROJECT_SOURCE_DIR}/src/aead.c
${PROJECT_SOURCE_DIR}/src/aead2022.c
${PROJECT_SOURCE_DIR}/src/aead2022_udp.c
${PROJECT_SOURCE_DIR}/src/ppbloom.c
${PROJECT_SOURCE_DIR}/src/cache.c
${PROJECT_SOURCE_DIR}/src/base64.c
${PROJECT_SOURCE_DIR}/src/ppbloom.cpp
${PROJECT_SOURCE_DIR}/src/cache.cpp
${PROJECT_SOURCE_DIR}/src/base64.cpp
${PROJECT_SOURCE_DIR}/src/utils.c
)
@@ -200,11 +220,11 @@ add_test(NAME test_ss_setup
set_tests_properties(test_ss_setup PROPERTIES LABELS "integration")
ss_add_test(test_ipset
"test_ipset.c;${PROJECT_SOURCE_DIR}/src/ipset.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_ipset.c;${PROJECT_SOURCE_DIR}/src/ipset.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"ss_sodium")
ss_add_test(test_process
"test_process.c;${PROJECT_SOURCE_DIR}/src/process.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"test_process.c;${PROJECT_SOURCE_DIR}/src/process.cpp;${PROJECT_SOURCE_DIR}/src/utils.c"
"ss_sodium")
set_tests_properties(test_process PROPERTIES TIMEOUT 20)
@@ -218,7 +238,7 @@ 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.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c"
"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_LITERAL_LIBS}")
ss_add_test(test_event "test_event.c" "ss_ev")