Squashed 'external/toxcore/c-toxcore/' changes from 1828c5356..c9cdae001

c9cdae001 fix(toxav): remove extra copy of video frame on encode
4f6d4546b test: Improve the fake network library.
a2581e700 refactor(toxcore): generate `Friend_Request` and `Dht_Nodes_Response`
2aaa11770 refactor(toxcore): use Tox_Memory in generated events
5c367452b test(toxcore): fix incorrect mutex in tox_scenario_get_time
8f92e710f perf: Add a timed limit of number of cookie requests.
695b6417a test: Add some more simulated network support.
815ae9ce9 test(toxcore): fix thread-safety in scenario framework
6d85c754e test(toxcore): add unit tests for net_crypto
9c22e79cc test(support): add SimulatedEnvironment for deterministic testing
f34fcb195 chore: Update windows Dockerfile to debian stable (trixie).
ece0e8980 fix(group_moderation): allow validating unsorted sanction list signatures
a4fa754d7 refactor: rename struct Packet to struct Net_Packet
d6f330f85 cleanup: Fix some warnings from coverity.
e206bffa2 fix(group_chats): fix sync packets reverting topics
0e4715598 test: Add new scenario testing framework.
668291f44 refactor(toxcore): decouple Network_Funcs from sockaddr via IP_Port
fc4396cef fix: potential division by zero in toxav and unsafe hex parsing
8e8b352ab refactor: Add nullable annotations to struct members.
7740bb421 refactor: decouple net_crypto from DHT
1936d4296 test: add benchmark for toxav audio and video
46bfdc2df fix: correct printf format specifiers for unsigned integers
REVERT: 1828c5356 fix(toxav): remove extra copy of video frame on encode

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: c9cdae001341e701fca980c9bb9febfeb95d2902
This commit is contained in:
Green Sky
2026-01-11 14:42:31 +01:00
parent e95f2cbb1c
commit 565efa4f39
328 changed files with 19057 additions and 13982 deletions

View File

@@ -4,11 +4,16 @@ CPPFLAGS="-DMIN_LOGGER_LEVEL=LOGGER_LEVEL_TRACE"
CPPFLAGS+=("-DCMP_NO_FLOAT=1")
CPPFLAGS+=("-isystem" "/usr/include/opus")
CPPFLAGS+=("-Iauto_tests")
CPPFLAGS+=("-Iauto_tests/scenarios")
CPPFLAGS+=("-Iauto_tests/scenarios/framework")
CPPFLAGS+=("-Iother")
CPPFLAGS+=("-Iother/bootstrap_daemon/src")
CPPFLAGS+=("-Iother/fun")
CPPFLAGS+=("-Itesting")
CPPFLAGS+=("-Itesting/fuzzing")
CPPFLAGS+=("-Itesting/support")
CPPFLAGS+=("-Itesting/support/doubles")
CPPFLAGS+=("-Itesting/support/public")
CPPFLAGS+=("-Itoxcore")
CPPFLAGS+=("-Itoxcore/events")
CPPFLAGS+=("-Itoxav")
@@ -49,29 +54,44 @@ callmain() {
# Include all C and C++ code
FIND_QUERY="find . '-(' -name '*.c' -or -name '*.cc' '-)'"
# Excludes
FIND_QUERY="$FIND_QUERY -and -not -wholename './_build/*'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './other/docker/*'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './super_donators/*'"
FIND_QUERY="$FIND_QUERY -and -not -name amalgamation.cc"
FIND_QUERY="$FIND_QUERY -and -not -name av_test.c"
FIND_QUERY="$FIND_QUERY -and -not -name cracker.c"
FIND_QUERY="$FIND_QUERY -and -not -name version_test.c"
FIND_QUERY="$FIND_QUERY -and -not -name '*_fuzz_test.cc'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './testing/fuzzing/*'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './third_party/cmp/examples/*'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './third_party/cmp/test/*'"
HEADER_QUERY="find . '-(' -name '*.h' -or -name '*.hh' '-)'"
if [ "$SKIP_GTEST" == 1 ]; then
FIND_QUERY="$FIND_QUERY -and -not -name '*_test.cc'"
COMMON_EXCLUDES=""
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './_build/*'"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './other/docker/*'"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './super_donators/*'"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './testing/fuzzing/*'"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './third_party/cmp/examples/*'"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -wholename './third_party/cmp/test/*'"
# File name excludes
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name amalgamation.cc"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name av_test.c"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name cracker.c"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name version_test.c"
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name '*_fuzz_test.cc'"
if [ "$SKIP_BENCHMARK" == 1 ]; then
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name '*_bench.cc'"
fi
readarray -t FILES <<<"$(eval "$FIND_QUERY")"
if [ "$SKIP_GTEST" == 1 ]; then
COMMON_EXCLUDES="$COMMON_EXCLUDES -and -not -name '*_test.cc'"
fi
(for i in "${FILES[@]}"; do
FIND_QUERY="$FIND_QUERY $COMMON_EXCLUDES"
HEADER_QUERY="$HEADER_QUERY $COMMON_EXCLUDES"
readarray -t FILES <<<"$(eval "$FIND_QUERY")"
readarray -t HEADERS <<<"$(eval "$HEADER_QUERY")"
INCLUDES=$(for i in "${FILES[@]}" "${HEADERS[@]}"; do
grep -o '#include <[^>]*>' "$i" |
grep -E -v '<win|<ws|<iphlp|<libc|<mach/|<crypto_|<randombytes|<u.h>|<sys/filio|<stropts.h>|<linux'
done) | sort -u >>amalgamation.cc
done | sort -u)
echo "$INCLUDES" | grep "<memory>" >>amalgamation.cc
echo "$INCLUDES" | grep -v "<memory>" >>amalgamation.cc
put auto_tests/check_compat.h

View File

@@ -36,7 +36,13 @@ run() {
-Wno-unreachable-code-return \
-Wno-unsafe-buffer-usage \
-Wno-unused-parameter \
-Wno-used-but-marked-unused
-Wno-used-but-marked-unused \
-Wno-unneeded-member-function \
-Wno-unused-function \
-Wno-unused-member-function \
-Wno-unused-parameter \
-Wno-unused-template
# TODO(iphydf): Remove these last 5 when the test framework matures.
}
. other/analysis/variants.sh

View File

@@ -9,7 +9,30 @@ run() {
clang++ --analyze amalgamation.cc \
"${CPPFLAGS[@]}" \
"$@" \
-std=c++20
-std=c++20 &
local pid=$!
local start_time="$(date +%s)"
local last_update="$start_time"
local timeout=$((30 * 60))
local interval=$((5 * 60))
while kill -0 "$pid" 2>/dev/null; do
local current_time="$(date +%s)"
if ((current_time - start_time > timeout)); then
echo "Timeout reached. Killing process."
kill -9 "$pid"
wait "$pid"
return 1
fi
if ((current_time - last_update > interval)); then
echo "Still running..."
last_update=$current_time
fi
sleep 1
done
wait "$pid"
}
. other/analysis/variants.sh

View File

@@ -16,8 +16,7 @@ CHECKS="$CHECKS,-clang-analyzer-nullability.NullPassedToNonnull"
# =========================================================
# TODO(iphydf): Fix these.
ERRORS="$ERRORS,-cert-err34-c"
ERRORS="$ERRORS,-readability-suspicious-call-argument"
CHECKS="$CHECKS,-readability-suspicious-call-argument"
CHECKS="$CHECKS,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto"
CHECKS="$CHECKS,-bugprone-incorrect-roundings"
@@ -193,12 +192,15 @@ CHECKS="$CHECKS,-cppcoreguidelines-macro-usage"
# These are all very C++ and/or LLVM specific.
CHECKS="$CHECKS,-llvmlibc-*"
# We use unions in C, and can't use std::variant or boost::variant.
CHECKS="$CHECKS,-cppcoreguidelines-pro-type-union-access"
set -eux
# TODO(iphydf): Add toxav.
DIRS=(
other/bootstrap_daemon/src
other
toxav
toxcore
toxcore/events
toxencryptsave

View File

@@ -1,6 +1,7 @@
#!/bin/bash
SKIP_GTEST=1
SKIP_BENCHMARK=1
. other/analysis/gen-file.sh
@@ -14,8 +15,6 @@ CPPCHECK+=("--library=other/docker/cppcheck/toxcore.cfg")
CPPCHECK+=("--error-exitcode=1")
# Some files don't match all our suppressions below.
CPPCHECK+=("--suppress=unmatchedSuppression")
# We don't cast function pointers, which cppcheck suggests here.
CPPCHECK+=("--suppress=constParameterCallback")
# This disagrees with clang's warnings.
CPPCHECK+=("--suppress=invalidPrintfArgType_uint")
# False positives in switch statements.
@@ -24,8 +23,11 @@ CPPCHECK+=("--suppress=knownConditionTrueFalse")
CPPCHECK+=("--suppress=missingIncludeSystem")
# TODO(iphydf): Maybe fix?
CPPCHECK+=("--suppress=signConversion")
# We have suppressions in the code for the misra extension.
CPPCHECK+=("--suppress=unmatchedSuppression")
# These const correctness checks are very broken for C.
CPPCHECK+=("--suppress=constParameter")
CPPCHECK+=("--suppress=constParameterCallback")
CPPCHECK+=("--suppress=constParameterPointer")
CPPCHECK+=("--suppress=constVariablePointer")
# We use this for VLAs.
CPPCHECK_CXX+=("--suppress=allocaCalled")

View File

@@ -65,7 +65,9 @@ run() {
-Wunused-value \
-Wunused-but-set-parameter \
-Wunused-but-set-variable \
-fopenmp
-fopenmp \
-Wno-unused-function
# TODO(iphydf): Remove this last 1 when the test framework matures.
}
. other/analysis/variants.sh

View File

@@ -312,6 +312,20 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char **
return true;
}
static int hex_digit_to_int(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
return -1;
}
/**
*
* Converts a hex string with even number of characters into binary.
@@ -337,9 +351,15 @@ static uint8_t *bootstrap_hex_string_to_bin(const char *hex_string)
const char *pos = hex_string;
for (size_t i = 0; i < len; ++i, pos += 2) {
unsigned int val;
sscanf(pos, "%02x", &val);
ret[i] = val;
const int hi = hex_digit_to_int(pos[0]);
const int lo = hex_digit_to_int(pos[1]);
if (hi == -1 || lo == -1) {
free(ret);
return nullptr;
}
ret[i] = (uint8_t)((hi << 4) | lo);
}
return ret;

View File

@@ -19,9 +19,9 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.2.20</string>
<string>0.2.21</string>
<key>CFBundleShortVersionString</key>
<string>0.2.20</string>
<string>0.2.21</string>
<key>CFBundleGetInfoString</key>
<string>Tox Framework</string>
</dict>

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "toxcore"
s.version = "0.2.20"
s.version = "0.2.21"
s.summary = "Cocoapods wrapper for toxcore"
s.homepage = "https://github.com/TokTok/c-toxcore"
s.license = 'GPLv3'

View File

@@ -6,10 +6,10 @@
#
# Example:
#
# other/deploy/single-file/make_single_file auto_tests/toxav_basic_test.c auto_tests/auto_test_support.c testing/misc_tools.c | \
# other/deploy/single-file/make_single_file auto_tests/scenarios/scenario_toxav_basic_test.c auto_tests/scenarios/framework/framework.c testing/misc_tools.c | \
# tcc -o toxav_basic_test - $(pkg-config --cflags --libs libsodium opus vpx)
#
# other/deploy/single-file/make_single_file -core auto_tests/send_message_test.c auto_tests/auto_test_support.c testing/misc_tools.c | \
# other/deploy/single-file/make_single_file -core auto_tests/scenarios/scenario_send_message_test.c auto_tests/scenarios/framework/framework.c testing/misc_tools.c | \
# tcc -o send_message_test - $(pkg-config --cflags --libs libsodium)
use strict;

View File

@@ -6,6 +6,7 @@
!*.spec.in
!**/Makefile.am
!**/Makefile.inc
!tools/*
!docs/updates/*
!other/DHTnodes
!other/astyle/*

View File

@@ -19,8 +19,8 @@ $(libsodium_OBJECTS): CFLAGS += \
-Ilibsodium/src/libsodium/include/sodium
toxcore_SOURCES := $(wildcard \
auto_tests/auto_test_support.c \
auto_tests/send_message_test.c \
auto_tests/scenarios/framework/framework.c \
auto_tests/scenarios/scenario_send_message_test.c \
testing/misc_tools.c \
toxav/*.c \
toxcore/*.c \

View File

@@ -16,4 +16,4 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium /work/libsodium
COPY other/docker/compcert/Makefile /work/
RUN make "-j$(nproc)"
RUN ./send_message_test | grep 'tox clients connected'
RUN ./send_message_test 2>&1 | grep 'Correctly failed to send too long message'

View File

@@ -42,6 +42,10 @@ SUPPRESSIONS += 10.8
#
# Reason: this is needed for generic callbacks to make any sense.
SUPPRESSIONS += 11.5
# A conversion shall not remove any const, volatile or _Atomic qualification from the type pointed to by a pointer.
#
# Reason: we need to cast from _Nullable to _Nonnull.
SUPPRESSIONS += 11.8
# The precedence of operators within expressions should be made explicit.
#
# Reason: this asks us to add a lot of extra parentheses that don't really help

View File

@@ -4,29 +4,43 @@ import os
import subprocess
import sys
from dataclasses import dataclass
from typing import Iterable
from typing import Optional
from dataclasses import field
from typing import Any
from typing import Dict
from typing import List
LIBS = {}
MODS = {}
STD_MODULE = """module std [system] {
textual header "/usr/include/alloca.h"
textual header "/usr/include/assert.h"
textual header "/usr/include/c++/14.2.0/algorithm"
textual header "/usr/include/c++/14.2.0/array"
textual header "/usr/include/c++/14.2.0/atomic"
textual header "/usr/include/c++/14.2.0/cassert"
textual header "/usr/include/c++/14.2.0/cerrno"
textual header "/usr/include/c++/14.2.0/chrono"
textual header "/usr/include/c++/14.2.0/climits"
textual header "/usr/include/c++/14.2.0/compare"
textual header "/usr/include/c++/14.2.0/cstddef"
textual header "/usr/include/c++/14.2.0/cstdint"
textual header "/usr/include/c++/14.2.0/cstdio"
textual header "/usr/include/c++/14.2.0/cstdlib"
textual header "/usr/include/c++/14.2.0/cstring"
textual header "/usr/include/c++/14.2.0/deque"
textual header "/usr/include/c++/14.2.0/functional"
textual header "/usr/include/c++/14.2.0/iomanip"
textual header "/usr/include/c++/14.2.0/iosfwd"
textual header "/usr/include/c++/14.2.0/iostream"
textual header "/usr/include/c++/14.2.0/limits"
textual header "/usr/include/c++/14.2.0/map"
textual header "/usr/include/c++/14.2.0/memory"
textual header "/usr/include/c++/14.2.0/mutex"
textual header "/usr/include/c++/14.2.0/new"
textual header "/usr/include/c++/14.2.0/optional"
textual header "/usr/include/c++/14.2.0/ostream"
textual header "/usr/include/c++/14.2.0/queue"
textual header "/usr/include/c++/14.2.0/random"
textual header "/usr/include/c++/14.2.0/stdlib.h"
textual header "/usr/include/c++/14.2.0/string"
textual header "/usr/include/c++/14.2.0/thread"
textual header "/usr/include/c++/14.2.0/type_traits"
textual header "/usr/include/c++/14.2.0/vector"
@@ -43,29 +57,33 @@ STD_MODULE = """module std [system] {
textual header "/usr/include/sys/types.h"
textual header "/usr/include/time.h"
}
module "//c-toxcore/third_party:cmp" {
module "c_toxcore_third_party_cmp" {
header "third_party/cmp/cmp.h"
use std
}
module "//c-toxcore/toxencryptsave:defines" {
module "c_toxcore_toxencryptsave_defines" {
header "toxencryptsave/defines.h"
}
module "@benchmark" {
module "_benchmark" {
textual header "/usr/include/benchmark/benchmark.h"
use std
}
module "@com_google_googletest//:gtest" {
module "_com_google_googletest___gtest" {
textual header "/usr/include/gmock/gmock.h"
textual header "/usr/include/gtest/gtest.h"
use std
}
module "@libsodium" {
module "_com_google_googletest___gtest_main" {
// Dummy module for gtest_main, assuming it links but headers are in gtest
use "_com_google_googletest___gtest"
}
module "_libsodium" {
textual header "/usr/include/sodium.h"
}
module "@pthread" {
module "_pthread" {
textual header "/usr/include/pthread.h"
}
module "@psocket" {
module "_psocket" {
textual header "/usr/include/arpa/inet.h"
textual header "/usr/include/fcntl.h"
textual header "/usr/include/fortify/sys/socket.h"
@@ -79,94 +97,132 @@ module "@psocket" {
@dataclass
class Context:
pkg: str
pkg_prefix: str
class Target:
name: str
package: str
srcs: List[str] = field(default_factory=list)
hdrs: List[str] = field(default_factory=list)
deps: List[str] = field(default_factory=list)
def bzl_load(self, bzl: str, *syms: str) -> None:
@property
def label(self) -> str:
# Sanitize label for module name
sanitized = (f"//c-toxcore/{self.package}:{self.name}".replace(
"/", "_").replace(":",
"_").replace(".",
"_").replace("-",
"_").replace("@", "_"))
if sanitized.startswith("__"):
sanitized = sanitized[2:]
return sanitized
TARGETS: List[Target] = []
class BuildContext:
def __init__(self, package: str):
self.package = package
def bzl_load(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_exports_files(
self,
srcs: list[str],
visibility: Optional[list[str]] = None,
) -> None:
def bzl_exports_files(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_cc_library(
self,
name: str,
srcs: Iterable[str] = tuple(),
hdrs: Iterable[str] = tuple(),
deps: Iterable[str] = tuple(),
visibility: Iterable[str] = tuple(),
testonly: bool = False,
copts: Iterable[str] = tuple(),
) -> None:
LIBS[name] = {
"srcs":
srcs,
"deps": [
f"{self.pkg_prefix}{dep}" if dep[0] == ":" else dep
for dep in deps
],
"hdrs":
hdrs,
}
def bzl_cc_binary(
self,
name: str,
srcs: Iterable[str] = tuple(),
hdrs: Iterable[str] = tuple(),
deps: Iterable[str] = tuple(),
**kwargs: list[str],
) -> None:
LIBS[name] = {
"srcs":
srcs,
"deps": [
f"{self.pkg_prefix}{dep}" if dep[0] == ":" else dep
for dep in deps
],
"hdrs":
hdrs,
}
def bzl_cc_fuzz_test(self, name: str, **kwargs: list[str]) -> None:
def bzl_alias(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_select(self, selector: dict[str, list[str]]) -> list[str]:
return selector["//tools/config:linux"]
def bzl_glob(self, include: list[str]) -> list[str]:
return [
f[len(self.pkg) + 1:] for p in include
for f in glob.glob(os.path.join(self.pkg, p))
]
def bzl_alias(self, name: str, actual: str, visibility: list[str]) -> None:
def bzl_sh_library(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_sh_library(self, name: str, **kwargs: list[str]) -> None:
def bzl_cc_fuzz_test(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_select(self, selector: Dict[str, List[str]]) -> List[str]:
return selector.get("//tools/config:linux",
selector.get("//conditions:default", []))
def bzl_glob(self, include: List[str]) -> List[str]:
results = []
for pattern in include:
full_pattern = os.path.join(self.package, pattern)
files = glob.glob(full_pattern)
results.extend([os.path.relpath(f, self.package) for f in files])
return results
def _add_target(self, name: str, srcs: Any, hdrs: Any, deps: Any) -> None:
srcs = list(srcs) if srcs else []
hdrs = list(hdrs) if hdrs else []
deps = list(deps) if deps else []
TARGETS.append(Target(name, self.package, srcs, hdrs, deps))
def bzl_cc_library(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def bzl_cc_binary(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def bzl_cc_test(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def resolve_module_name(dep: str, current_pkg: str) -> str:
# Resolve to canonical label first
label = dep
if dep.startswith("@"):
label = dep
elif dep.startswith("//"):
if ":" in dep:
label = dep
else:
pkg_name = os.path.basename(dep)
label = f"{dep}:{pkg_name}"
elif dep.startswith(":"):
label = f"//c-toxcore/{current_pkg}{dep}"
# Sanitize
sanitized = (label.replace("/", "_").replace(":", "_").replace(
".", "_").replace("-", "_").replace("@", "_"))
if sanitized.startswith("__"):
sanitized = sanitized[2:]
return sanitized
def main() -> None:
srcs: list[str] = []
for pkg in ("toxcore", ):
# TODO(iphydf): Why does this break everything?
# ctx = Context(pkg, "//c-toxcore/{pkg}")
ctx = Context(pkg, "")
with open(os.path.join(pkg, "BUILD.bazel"), "r") as fh:
packages = ["toxcore", "testing/support"]
for pkg in packages:
ctx = BuildContext(pkg)
build_file = os.path.join(pkg, "BUILD.bazel")
if not os.path.exists(build_file):
continue
with open(build_file, "r") as f:
exec(
fh.read(),
f.read(),
{
"load": ctx.bzl_load,
"exports_files": ctx.bzl_exports_files,
"cc_library": ctx.bzl_cc_library,
"cc_binary": ctx.bzl_cc_binary,
"cc_test": ctx.bzl_cc_binary,
"cc_test": ctx.bzl_cc_test,
"cc_fuzz_test": ctx.bzl_cc_fuzz_test,
"select": ctx.bzl_select,
"glob": ctx.bzl_glob,
@@ -175,36 +231,36 @@ def main() -> None:
},
)
with open("module.modulemap", "w") as fh:
fh.write(STD_MODULE)
for name, lib in LIBS.items():
fh.write(f'module "{ctx.pkg_prefix}:{name}"' + " {\n")
for hdr in lib["hdrs"]:
fh.write(f' header "{pkg}/{hdr}"\n')
fh.write(f" use std\n")
for dep in lib.get("deps", []):
fh.write(f' use "{dep}"\n')
fh.write("}\n")
with open("module.modulemap", "w") as f:
f.write(STD_MODULE)
for t in TARGETS:
f.write(f'module "{t.label}" {{\n')
for hdr in t.hdrs:
f.write(f' header "{os.path.join(t.package, hdr)}"\n')
f.write(" use std\n")
for dep in t.deps:
mod_name = resolve_module_name(dep, t.package)
# Export all dependencies to ensure visibility of types used in headers
f.write(f" use {mod_name}\n")
f.write(f" export {mod_name}\n")
f.write("}\n")
for name, lib in LIBS.items():
for src in lib.get("srcs", []):
MODS[os.path.join(pkg, src)] = name
srcs.extend(
os.path.join(pkg, src) # just within a package for now
for lib in LIBS.values() for src in lib.get("srcs", []))
# subprocess.run(["cat", "module.modulemap"], check=True)
for src in sorted(
set(srcs) - set([
# TODO(iphydf): Figure out what's wrong here.
"toxcore/crypto_core_test.cc",
"toxcore/group_announce_test.cc",
"toxcore/group_moderation_test.cc",
"toxcore/mono_time_test.cc",
"toxcore/network_test.cc",
"toxcore/ping_array_test.cc",
"toxcore/util_test.cc",
])):
# with open("module.modulemap", "r") as f:
# print(f.read(), file=sys.stderr)
src_to_module = {}
for t in TARGETS:
for src in t.srcs:
full_src = os.path.join(t.package, src)
src_to_module[full_src] = t.label
# Sort for deterministic output
all_srcs = sorted(src_to_module.keys())
for src in all_srcs:
print(f"Validating {src}", file=sys.stderr)
module_name = src_to_module[src]
subprocess.run(
[
"clang",
@@ -219,7 +275,8 @@ def main() -> None:
"-fmodules",
"-fmodules-strict-decluse",
"-fmodule-map-file=module.modulemap",
f"-fmodule-name={ctx.pkg_prefix}:{MODS[src]}",
f"-fmodule-name={module_name}",
"-I.",
src,
],
check=True,

View File

@@ -1,5 +1,6 @@
SOURCES := auto_tests/send_message_test.c \
auto_tests/auto_test_support.c \
SOURCES := \
auto_tests/scenarios/framework/framework.c \
auto_tests/scenarios/scenario_send_message_test.c \
testing/misc_tools.c \
$(wildcard tox*/*.c tox*/*/*.c) \
third_party/cmp/cmp.c

View File

@@ -41,4 +41,4 @@ COPY other/docker/slimcc/Makefile /work/c-toxcore/
RUN ["make"]
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN ./send_message_test | grep "tox clients connected"
RUN ./send_message_test 2>&1 | grep "Correctly failed to send too long message"

View File

@@ -22,8 +22,8 @@ RUN tcc \
-o send_message_test \
-Wall -Werror \
-bench -g \
auto_tests/auto_test_support.c \
auto_tests/send_message_test.c \
auto_tests/scenarios/framework/framework.c \
auto_tests/scenarios/scenario_send_message_test.c \
testing/misc_tools.c \
toxav/*.c \
toxcore/*.c \
@@ -31,29 +31,29 @@ RUN tcc \
toxencryptsave/*.c \
third_party/cmp/*.c \
$(pkg-config --cflags --libs libsodium opus vpx) \
&& ./send_message_test | grep 'tox clients connected'
&& ./send_message_test 2>&1 | grep 'Correctly failed to send too long message'
COPY other/deploy/single-file/make_single_file /work/
RUN \
./make_single_file -core \
auto_tests/auto_test_support.c \
auto_tests/send_message_test.c \
auto_tests/scenarios/framework/framework.c \
auto_tests/scenarios/scenario_send_message_test.c \
testing/misc_tools.c | \
tcc - \
-o send_message_test \
-Wall -Werror \
-bench -g \
$(pkg-config --cflags --libs libsodium) \
&& ./send_message_test | grep 'tox clients connected'
&& ./send_message_test 2>&1 | grep 'Correctly failed to send too long message'
RUN \
./make_single_file \
auto_tests/auto_test_support.c \
auto_tests/toxav_basic_test.c \
auto_tests/scenarios/framework/framework.c \
auto_tests/scenarios/scenario_toxav_basic_test.c \
testing/misc_tools.c | \
tcc - \
-o toxav_basic_test \
-Wall -Werror \
-bench -g \
$(pkg-config --cflags --libs libsodium opus vpx) \
&& ./toxav_basic_test | grep 'Test successful'
&& ./toxav_basic_test 2>&1 | grep 'Cancel Flow finished'

View File

@@ -1,4 +1,4 @@
FROM debian:bookworm-slim
FROM debian:trixie-slim
# When editing, make sure to update /other/windows_build_script_toxcore.sh and
# INSTALL.md to match.

View File

@@ -56,7 +56,7 @@ build() {
" >windows_toolchain.cmake
if [ "$ENABLE_TEST" = "true" ]; then
echo "SET(CROSSCOMPILING_EMULATOR /usr/bin/wine)" >>windows_toolchain.cmake
echo "SET(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/wine)" >>windows_toolchain.cmake
fi
if [ "$ARCH" = "i686" ]; then

View File

@@ -43,19 +43,19 @@ if [ "$SUPPORT_TEST" = "true" ]; then
CURL_OPTIONS=(-L --connect-timeout 10)
# While we would prefer to use Debian's Wine packages, use WineHQ's packages
# instead as Debian Bookworm's Wine crashes when creating a 64-bit prefix.
# instead as Debian Trixie's Wine crashes when creating a 64-bit prefix.
# see https://github.com/TokTok/c-toxcore/pull/2713#issuecomment-1967319113
# for the crash details
curl "${CURL_OPTIONS[@]}" -o /etc/apt/keyrings/winehq-archive.key \
https://dl.winehq.org/wine-builds/winehq.key
curl "${CURL_OPTIONS[@]}" -O --output-dir /etc/apt/sources.list.d/ \
https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources
https://dl.winehq.org/wine-builds/debian/dists/trixie/winehq-trixie.sources
. ./check_sha256.sh
check_sha256 "d965d646defe94b3dfba6d5b4406900ac6c81065428bf9d9303ad7a72ee8d1b8" \
"/etc/apt/keyrings/winehq-archive.key"
check_sha256 "8dd8ef66c749d56e798646674c1c185a99b3ed6727ca0fbb5e493951e66c0f9e" \
"/etc/apt/sources.list.d/winehq-bookworm.sources"
check_sha256 "d10fb49718b5ceda9cc9c2f8f52b076772396b4b3563a1aad2ab6503414dcee7" \
"/etc/apt/sources.list.d/winehq-trixie.sources"
dpkg --add-architecture i386
apt-get update

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright © 2023-2025 The TokTok team.
// Copyright © 2023-2026 The TokTok team.
// this file can be used to generate event.c files
// requires c++17
@@ -27,6 +27,7 @@ std::string output_folder = "out";
struct EventTypeTrivial {
std::string type; // eg uint32_t
std::string name; // eg friend_number
std::string cb_type = "";
};
struct EventTypeByteRange {
@@ -34,11 +35,17 @@ struct EventTypeByteRange {
std::string name_data; // eg data
std::string name_length; // eg data_length
std::string name_length_cb; // eg length // TODO: merge with normal?
std::string type_c_arg = "uint8_t";
std::string type_length_cb = "size_t";
bool null_terminated = false;
};
// TODO: EventTypeByteArray
struct EventTypeByteArray {
std::string name; // eg public_key
std::string length_constant; // eg TOX_PUBLIC_KEY_SIZE;
};
using EventType = std::variant<EventTypeTrivial, EventTypeByteRange>;
using EventType = std::variant<EventTypeTrivial, EventTypeByteRange, EventTypeByteArray>;
// helper type for the visitor #4
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
@@ -125,6 +132,40 @@ std::string bin_unpack_name_from_type(const std::string& type) {
}
}
std::string zero_initializer_for_type(const std::string& type) {
if (type == "uint64_t" || type == "uint32_t" || type == "uint16_t" || type == "uint8_t") {
return "0";
} else if (type == "bool") {
return "false";
} else if (type == "Tox_User_Status") {
return "TOX_USER_STATUS_NONE";
} else if (type == "Tox_Conference_Type") {
return "TOX_CONFERENCE_TYPE_TEXT";
} else if (type == "Tox_Message_Type") {
return "TOX_MESSAGE_TYPE_NORMAL";
} else if (type == "Tox_File_Control") {
return "TOX_FILE_CONTROL_RESUME";
} else if (type == "Tox_Connection") {
return "TOX_CONNECTION_NONE";
} else if (type == "Tox_Group_Privacy_State") {
return "TOX_GROUP_PRIVACY_STATE_PUBLIC";
} else if (type == "Tox_Group_Voice_State") {
return "TOX_GROUP_VOICE_STATE_NON_MUTED";
} else if (type == "Tox_Group_Topic_Lock") {
return "TOX_GROUP_TOPIC_LOCK_UNLOCKED";
} else if (type == "Tox_Group_Join_Fail") {
return "TOX_GROUP_JOIN_FAIL_NULL";
} else if (type == "Tox_Group_Mod_Event") {
return "TOX_GROUP_MOD_EVENT_MOD";
} else if (type == "Tox_Group_Exit_Type") {
return "TOX_GROUP_EXIT_TYPE_KICK";
} else {
std::cerr << "unknown type " << type << "\n";
exit(1);
return "0";
}
}
void generate_event_impl(const std::string& event_name, const std::vector<EventType>& event_types) {
const std::string event_name_l = str_tolower(event_name);
std::string file_name = output_folder + "/" + event_name_l + ".c";
@@ -135,7 +176,6 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
exit(1);
}
bool need_stdlib_h = false;
bool need_string_h = false;
bool need_tox_unpack_h = false;
for (const auto& t : event_types) {
@@ -147,7 +187,9 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
}
},
[&](const EventTypeByteRange&) {
need_stdlib_h = true;
need_string_h = true;
},
[&](const EventTypeByteArray&) {
need_string_h = true;
}
},
@@ -156,16 +198,12 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
}
f << R"(/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2023-2025 The TokTok team.
* Copyright © 2023-2026 The TokTok team.
*/
#include "events_alloc.h"
#include <assert.h>)";
if (need_stdlib_h) {
f << R"(
#include <stdlib.h>)";
}
if (need_string_h) {
f << R"(
#include <string.h>)";
@@ -206,6 +244,9 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
[&](const EventTypeByteRange& t) {
f << " " << "uint8_t" << " *" << t.name_data << ";\n";
f << " " << "uint32_t" << " " << t.name_length << ";\n";
},
[&](const EventTypeByteArray& t) {
f << " uint8_t " << t.name << "[" << t.length_constant << "];\n";
}
},
t
@@ -224,6 +265,9 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
},
[&](const EventTypeByteRange& t) {
f << t.name_data;
},
[&](const EventTypeByteArray& t) {
f << t.name;
}
},
t
@@ -235,7 +279,10 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
f << " " << t.type << " " << t.name << ")\n";
},
[&](const EventTypeByteRange& t) {
f << "\n const uint8_t *_Nullable " << t.name_data << ", uint32_t " << t.name_length << ")\n";
f << "\n const Memory *_Nonnull mem, const uint8_t *_Nullable " << t.name_data << ", uint32_t " << t.name_length << ")\n";
},
[&](const EventTypeByteArray& t) {
f << " const uint8_t " << t.name << "[" << t.length_constant << "])\n";
}
},
t
@@ -248,20 +295,31 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
},
[&](const EventTypeByteRange& t) {
f << " if (" << event_name_l << "->" << t.name_data << " != nullptr) {\n";
f << " free(" << event_name_l << "->" << t.name_data << ");\n";
f << " mem_delete(mem, " << event_name_l << "->" << t.name_data << ");\n";
f << " " << event_name_l << "->" << t.name_data << " = nullptr;\n";
f << " " << event_name_l << "->" << t.name_length << " = 0;\n";
f << " }\n\n";
f << " if (" << t.name_data << " == nullptr) {\n";
f << " assert(" << t.name_length << " == 0);\n";
f << " return true;\n }\n\n";
f << " uint8_t *" << t.name_data << "_copy = (uint8_t *)malloc(" << t.name_length << ");\n\n";
if (t.null_terminated) {
f << " uint8_t *" << t.name_data << "_copy = (uint8_t *)mem_balloc(mem, " << t.name_length << " + 1);\n\n";
} else {
f << " uint8_t *" << t.name_data << "_copy = (uint8_t *)mem_balloc(mem, " << t.name_length << ");\n\n";
}
f << " if (" << t.name_data << "_copy == nullptr) {\n";
f << " return false;\n }\n\n";
f << " memcpy(" << t.name_data << "_copy, " << t.name_data << ", " << t.name_length << ");\n";
if (t.null_terminated) {
f << " " << t.name_data << "_copy[" << t.name_length << "] = 0;\n";
}
f << " " << event_name_l << "->" << t.name_data << " = " << t.name_data << "_copy;\n";
f << " " << event_name_l << "->" << t.name_length << " = " << t.name_length << ";\n";
f << " return true;\n";
},
[&](const EventTypeByteArray& t) {
f << " memcpy(" << event_name_l << "->" << t.name << ", " << t.name << ", " << t.length_constant << ");\n";
f << " return true;\n";
}
},
t
@@ -288,6 +346,12 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
f << "(const Tox_Event_" << event_name << " *" << event_name_l << ")\n";
f << "{\n assert(" << event_name_l << " != nullptr);\n";
f << " return " << event_name_l << "->" << t.name_data << ";\n}\n\n";
},
[&](const EventTypeByteArray& t) {
f << "const uint8_t *tox_event_" << event_name_l << "_get_" << t.name;
f << "(const Tox_Event_" << event_name << " *" << event_name_l << ")\n";
f << "{\n assert(" << event_name_l << " != nullptr);\n";
f << " return " << event_name_l << "->" << t.name << ";\n}\n\n";
}
},
t
@@ -297,10 +361,28 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
// gen contruct
f << "static void tox_event_" << event_name_l << "_construct(Tox_Event_" << event_name << " *_Nonnull " << event_name_l << ")\n{\n";
// TODO: initialize all members properly
// TODO: check if _NONE is universal
// str_toupper(
f << " *" << event_name_l << " = (Tox_Event_" << event_name << ") {\n 0\n };\n}\n";
f << " *" << event_name_l << " = (Tox_Event_" << event_name << ") {\n";
if (!event_types.empty()) {
std::visit(
overloaded{
[&](const EventTypeTrivial& t) {
f << " " << zero_initializer_for_type(t.type);
},
[&](const EventTypeByteRange& t) {
f << " nullptr";
},
[&](const EventTypeByteArray& t) {
f << " {\n 0\n }";
}
},
event_types[0]
);
} else {
f << " 0";
}
f << "\n };\n}\n";
// gen destruct
f << "static void tox_event_" << event_name_l << "_destruct(Tox_Event_" << event_name << " *_Nonnull " << event_name_l << ", const Memory *_Nonnull mem)\n{\n";
@@ -310,10 +392,11 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
overloaded{
[&](const EventTypeTrivial&) {},
[&](const EventTypeByteRange& t) {
f << " free(" << event_name_l << "->" << t.name_data << ");\n";
f << " mem_delete(mem, " << event_name_l << "->" << t.name_data << ");\n";
//f << " mem->funcs->free(mem->obj, " << event_name_l << "->" << t.name_data << ");\n";
data_count++;
}
},
[&](const EventTypeByteArray&) {}
},
t
);
@@ -353,6 +436,9 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
},
[&](const EventTypeByteRange& t) {
f << "bin_pack_bin(bp, event->" << t.name_data << ", event->" << t.name_length << ")";
},
[&](const EventTypeByteArray& t) {
f << "bin_pack_bin(bp, event->" << t.name << ", " << t.length_constant << ")";
}
},
t
@@ -386,6 +472,9 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
},
[&](const EventTypeByteRange& t) {
f << "bin_unpack_bin(bu, &event->" << t.name_data << ", &event->" << t.name_length << ")";
},
[&](const EventTypeByteArray& t) {
f << "bin_unpack_bin_fixed(bu, event->" << t.name << ", " << t.length_constant << ")";
}
},
t
@@ -417,7 +506,7 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
// free
f << "void tox_event_" << event_name_l << "_free(Tox_Event_" << event_name << " *" << event_name_l << ", const Memory *mem)\n{\n";
f << " if (" << event_name_l << " != nullptr) {\n";
f << " tox_event_" << event_name_l << "_destruct(" << event_name_l << ", mem);\n }\n";
f << " tox_event_" << event_name_l << "_destruct((Tox_Event_" << event_name << " * _Nonnull)" << event_name_l << ", mem);\n }\n";
f << " mem_delete(mem, " << event_name_l << ");\n}\n\n";
// add
@@ -444,9 +533,7 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
f << " return tox_event_" << event_name_l << "_unpack_into(*event, bu);\n}\n\n";
// alloc
f << "static Tox_Event_" << event_name << " *tox_event_" << event_name_l << "_alloc(void *_Nonnull user_data)\n{\n";
f << " Tox_Events_State *state = tox_events_alloc(user_data);\n";
f << " assert(state != nullptr);\n\n";
f << "static Tox_Event_" << event_name << " *tox_event_" << event_name_l << "_alloc(Tox_Events_State *_Nonnull state)\n{\n";
f << " if (state->events == nullptr) {\n return nullptr;\n }\n\n";
f << " Tox_Event_" << event_name << " *" << event_name_l << " = tox_events_add_" << event_name_l << "(state->events, state->mem);\n\n";
f << " if (" << event_name_l << " == nullptr) {\n";
@@ -469,10 +556,13 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
std::visit(
overloaded{
[&](const EventTypeTrivial& t) {
f << ", " << t.type << " " << t.name;
f << ", " << (t.cb_type.empty() ? t.type : t.cb_type) << " " << t.name;
},
[&](const EventTypeByteRange& t) {
f << ", const uint8_t *" << t.name_data << ", size_t " << t.name_length_cb;
f << ", const " << t.type_c_arg << " *" << t.name_data << ", " << t.type_length_cb << " " << t.name_length_cb;
},
[&](const EventTypeByteArray& t) {
f << ", const uint8_t *" << t.name;
}
},
t
@@ -480,7 +570,8 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
}
f << ",\n void *user_data)\n{\n";
f << " Tox_Event_" << event_name << " *" << event_name_l << " = tox_event_" << event_name_l << "_alloc(user_data);\n\n";
f << " Tox_Events_State *state = tox_events_alloc(user_data);\n";
f << " Tox_Event_" << event_name << " *" << event_name_l << " = tox_event_" << event_name_l << "_alloc(state);\n\n";
f << " if (" << event_name_l << " == nullptr) {\n return;\n }\n\n";
for (const auto& t : event_types) {
@@ -490,7 +581,14 @@ void generate_event_impl(const std::string& event_name, const std::vector<EventT
f << " tox_event_" << event_name_l << "_set_" << t.name << "(" << event_name_l << ", " << t.name << ");\n";
},
[&](const EventTypeByteRange& t) {
f << " tox_event_" << event_name_l << "_set_" << t.name_data << "(" << event_name_l << ", " << t.name_data << ", " << t.name_length_cb << ");\n";
f << " tox_event_" << event_name_l << "_set_" << t.name_data << "(" << event_name_l << ", state->mem, ";
if (t.type_c_arg != "uint8_t") {
f << "(const uint8_t *)";
}
f << t.name_data << ", " << t.name_length_cb << ");\n";
},
[&](const EventTypeByteArray& t) {
f << " tox_event_" << event_name_l << "_set_" << t.name << "(" << event_name_l << ", " << t.name << ");\n";
}
},
t
@@ -548,14 +646,21 @@ int main(int argc, char** argv) {
EventTypeByteRange{"title", "title_length", "length"}, // the latter two are ideally the same
}
},
{
"Dht_Nodes_Response",
{
EventTypeByteArray{"public_key", "TOX_PUBLIC_KEY_SIZE"},
EventTypeByteRange{"ip", "ip_length", "ip_length", "char", "uint32_t", true},
EventTypeTrivial{"uint16_t", "port"},
}
},
{
"File_Chunk_Request",
{
EventTypeTrivial{"uint32_t", "friend_number"},
EventTypeTrivial{"uint32_t", "file_number"},
EventTypeTrivial{"uint64_t", "position"},
EventTypeTrivial{"uint16_t", "length"},
EventTypeTrivial{"uint16_t", "length", "size_t"},
}
},
{
@@ -629,15 +734,13 @@ int main(int argc, char** argv) {
EventTypeTrivial{"uint32_t", "message_id"},
}
},
#if 0
{
"Friend_Request",
{
//EventTypeTrivial{"uint32_t", "friend_number"}, // public_key ByteArray
EventTypeByteArray{"public_key", "TOX_PUBLIC_KEY_SIZE"},
EventTypeByteRange{"message", "message_length", "length"}, // the latter two are ideally the same
}
},
#endif
{
"Friend_Status",
{