c-toxcore-0.2.20/0000755060175106017510000000000014714257602011476 5ustar robinc-toxcore-0.2.20/.circleci/0000755060175106017510000000000014714247532013332 5ustar robinc-toxcore-0.2.20/.circleci/bazel-test0000755060175106017510000000052714714247532015336 0ustar robin#!/bin/sh set -eux git submodule update --init --recursive /src/workspace/tools/inject-repo c-toxcore # TODO(iphydf): Re-enable fuzz-test when https://github.com/tweag/rules_nixpkgs/issues/442 is fixed. cd /src/workspace && bazel test -k \ --build_tag_filters=-haskell,-fuzz-test \ --test_tag_filters=-haskell,-fuzz-test \ -- \ "$@" c-toxcore-0.2.20/.circleci/cmake-asan0000755060175106017510000000212514714247532015260 0ustar robin#!/bin/bash set -eu CACHEDIR="$HOME/cache" . ".github/scripts/flags-$CC.sh" add_flag -Werror add_flag -fdiagnostics-color=always add_flag -fno-omit-frame-pointer add_flag -fsanitize=address cmake -B_build -H. -GNinja \ -DCMAKE_C_FLAGS="$C_FLAGS" \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_INSTALL_PREFIX:PATH="$PWD/_install" \ -DCMAKE_UNITY_BUILD=ON \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON \ -DBUILD_MISC_TESTS=ON \ -DBUILD_FUN_UTILS=ON cd _build ninja install -j"$(nproc)" export ASAN_OPTIONS="color=always" export ASAN_OPTIONS="$ASAN_OPTIONS,detect_invalid_pointer_pairs=1" export ASAN_OPTIONS="$ASAN_OPTIONS,detect_stack_use_after_return=1" export ASAN_OPTIONS="$ASAN_OPTIONS,strict_init_order=1" export ASAN_OPTIONS="$ASAN_OPTIONS,strict_string_checks=1" export ASAN_OPTIONS="$ASAN_OPTIONS,symbolize=1" ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 c-toxcore-0.2.20/.circleci/cmake-tsan0000755060175106017510000000162714714247532015311 0ustar robin#!/bin/bash set -eu CACHEDIR="$HOME/cache" . ".github/scripts/flags-$CC.sh" add_flag -Werror add_flag -fdiagnostics-color=always add_flag -fno-omit-frame-pointer add_flag -fsanitize=thread cmake -B_build -H. -GNinja \ -DCMAKE_C_FLAGS="$C_FLAGS" \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_INSTALL_PREFIX:PATH="$PWD/_install" \ -DCMAKE_UNITY_BUILD=ON \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cd _build ninja install -j"$(nproc)" export TSAN_OPTIONS="color=always" export TSAN_OPTIONS="$TSAN_OPTIONS,halt_on_error=1" export TSAN_OPTIONS="$TSAN_OPTIONS,second_deadlock_stack=1" export TSAN_OPTIONS="$TSAN_OPTIONS,symbolize=1" ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 c-toxcore-0.2.20/.circleci/cmake-ubsan0000755060175106017510000000241414714247532015447 0ustar robin#!/bin/bash set -eu CACHEDIR="$HOME/cache" . ".github/scripts/flags-$CC.sh" add_flag -Werror add_flag -D_DEBUG add_flag -fdiagnostics-color=always add_flag -fno-omit-frame-pointer add_flag -fno-sanitize-recover=all add_flag -fsanitize=undefined,nullability,local-bounds,float-divide-by-zero,integer add_flag -fno-sanitize=implicit-conversion,unsigned-integer-overflow # Enable extra checks. We only do this on ubsan because it shows useful error # messages for the kind of bugs this catches (mostly incorrect nullability # annotations). Other builds will segfault, ubsan will show a stack trace. add_flag -D_DEBUG cmake -B_build -H. -GNinja \ -DCMAKE_C_FLAGS="$C_FLAGS" \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_INSTALL_PREFIX:PATH="$PWD/_install" \ -DCMAKE_UNITY_BUILD=ON \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cd _build ninja install -j"$(nproc)" export UBSAN_OPTIONS="color=always" export UBSAN_OPTIONS="$UBSAN_OPTIONS,print_stacktrace=1" export UBSAN_OPTIONS="$UBSAN_OPTIONS,symbolize=1" ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 c-toxcore-0.2.20/.circleci/config.yml0000644060175106017510000000633214714247532015326 0ustar robin--- version: 2 workflows: version: 2 program-analysis: jobs: # Dynamic analysis in the Bazel build - bazel-asan - bazel-msan - bazel-tsan # Dynamic analysis with CMake - asan - tsan - ubsan # Static analysis - clang-analyze - cpplint - static-analysis jobs: bazel-asan: working_directory: /tmp/cirrus-ci-build docker: - image: toxchat/toktok-stack:latest-asan steps: - checkout - run: .circleci/bazel-test //c-toxcore/... bazel-tsan: working_directory: /tmp/cirrus-ci-build docker: - image: toxchat/toktok-stack:latest-tsan steps: - checkout - run: .circleci/bazel-test //c-toxcore/... -//c-toxcore/auto_tests:conference_av_test -//c-toxcore/auto_tests:conference_test -//c-toxcore/auto_tests:onion_test -//c-toxcore/auto_tests:tox_many_test bazel-msan: working_directory: /tmp/cirrus-ci-build docker: - image: toxchat/toktok-stack:latest-msan steps: - checkout - run: .circleci/bazel-test //c-toxcore/auto_tests:lossless_packet_test asan: working_directory: ~/work docker: - image: ubuntu steps: - run: &apt_install apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates clang cmake git libconfig-dev libgmock-dev libgtest-dev libopus-dev libsodium-dev libvpx-dev llvm-dev ninja-build pkg-config - checkout - run: git submodule update --init --recursive - run: CC=clang .circleci/cmake-asan tsan: working_directory: ~/work docker: - image: ubuntu steps: - run: *apt_install - checkout - run: git submodule update --init --recursive - run: CC=clang .circleci/cmake-tsan ubsan: working_directory: ~/work docker: - image: ubuntu steps: - run: *apt_install - checkout - run: git submodule update --init --recursive - run: CC=clang .circleci/cmake-ubsan static-analysis: working_directory: ~/work docker: - image: ubuntu steps: - run: *apt_install - run: apt-get install -y --no-install-recommends ca-certificates g++ llvm-dev - checkout - run: git submodule update --init --recursive - run: other/analysis/check_includes - run: other/analysis/check_logger_levels - run: other/analysis/run-clang - run: other/analysis/run-gcc clang-analyze: working_directory: ~/work docker: - image: ubuntu steps: - run: *apt_install - checkout - run: git submodule update --init --recursive - run: other/analysis/run-clang-analyze cpplint: working_directory: ~/work docker: - image: ubuntu steps: - run: *apt_install - run: apt-get install -y --no-install-recommends cpplint - checkout - run: git submodule update --init --recursive - run: other/analysis/run-cpplint c-toxcore-0.2.20/.cirrus.yml0000644060175106017510000000452314714247532013613 0ustar robin--- bazel-opt_task: timeout_in: 5m container: image: toxchat/toktok-stack:latest-release cpu: 2 memory: 2G configure_script: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - cd /src/workspace && bazel test -k --remote_cache=http://$CIRRUS_HTTP_CACHE_HOST --build_tag_filters=-haskell --test_tag_filters=-haskell -- //c-toxcore/... -//c-toxcore/auto_tests:tcp_relay_test # Cirrus doesn't allow external network connections. bazel-dbg_task: timeout_in: 5m container: image: toxchat/toktok-stack:latest-debug cpu: 2 memory: 2G configure_script: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - cd /src/workspace && bazel test -k --remote_cache=http://$CIRRUS_HTTP_CACHE_HOST --build_tag_filters=-haskell --test_tag_filters=-haskell -- //c-toxcore/... -//c-toxcore/auto_tests:tcp_relay_test # Cirrus doesn't allow external network connections. cimple_task: timeout_in: 5m container: image: toxchat/toktok-stack:latest-release cpu: 2 memory: 4G configure_script: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - cd /src/workspace && bazel test -k --remote_cache=http://$CIRRUS_HTTP_CACHE_HOST --build_tag_filters=haskell --test_tag_filters=haskell -- //c-toxcore/... freebsd_task: timeout_in: 5m freebsd_instance: image_family: freebsd-14-1 configure_script: - PAGER=cat ASSUME_ALWAYS_YES=YES pkg install cmake git gmake googletest libconfig libsodium libvpx opus pkgconf - git submodule update --init --recursive test_all_script: - | # TODO(iphydf): Investigate FreeBSD failures on these tests. sed -Ei -e '/\(dht_getnodes_api\)/s/^/#/' auto_tests/CMakeLists.txt cmake . \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=OFF \ -DTEST_TIMEOUT_SECONDS=50 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cmake --build . --target install ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 c-toxcore-0.2.20/.clang-format0000644060175106017510000000106214714247532014051 0ustar robinBasedOnStyle: WebKit ColumnLimit: 100 PointerAlignment: Right SpacesBeforeTrailingComments: 2 AlignConsecutiveMacros: true AlignEscapedNewlines: Left AlwaysBreakTemplateDeclarations: Yes SpaceBeforeCpp11BracedList: false Cpp11BracedListStyle: true IncludeIsMainRegex: '([-_](test|fuzz_test))?$' IncludeBlocks: Regroup IncludeCategories: - Regex: '^<.*\.h>' Priority: 1 SortPriority: 0 - Regex: '^<.*' Priority: 2 SortPriority: 0 - Regex: '.*' Priority: 3 SortPriority: 0 c-toxcore-0.2.20/.clang-tidy0000644060175106017510000000543214714247532013537 0ustar robin# vim:ft=yaml HeaderFilterRegex: "/c-toxcore/[^/]+/[^.].+" CheckOptions: - key: readability-identifier-naming.ClassCase value: Camel_Snake_Case - key: readability-identifier-naming.ConstantCase value: lower_case # bootstrap-daemon has these. - key: readability-identifier-naming.ConstantIgnoredRegexp value: "^NAME_.*" - key: readability-identifier-naming.EnumCase value: Camel_Snake_Case - key: readability-identifier-naming.EnumConstantCase value: UPPER_CASE - key: readability-identifier-naming.FunctionCase value: lower_case - key: readability-identifier-naming.GlobalConstantCase value: lower_case - key: readability-identifier-naming.MemberCase value: lower_case - key: readability-identifier-naming.MacroDefinitionCase value: UPPER_CASE - key: readability-identifier-naming.MacroDefinitionIgnoredRegexp value: "^_.*|bitwise|force|nullable|non_null|nullptr|static_assert|ck_.*" - key: readability-identifier-naming.ParameterCase value: lower_case - key: readability-identifier-naming.StructCase value: Camel_Snake_Case - key: readability-identifier-naming.TypedefCase value: Camel_Snake_Case - key: readability-identifier-naming.TypedefIgnoredRegexp value: ".*_cb" - key: readability-identifier-naming.UnionCase value: Camel_Snake_Case - key: readability-identifier-naming.VariableCase value: lower_case - key: llvmlibc-restrict-system-libc-headers.Includes value: "alloca.h,arpa/inet.h,assert.h,ctype.h,errno.h,fcntl.h,getopt.h,libconfig.h,limits.h,linux/if.h,math.h,netdb.h,netinet/in.h,opus.h,pthread.h,signal.h,sodium/crypto_scalarmult_curve25519.h,sodium.h,sodium/randombytes.h,stdarg.h,stdbool.h,stddef.h,stdint.h,stdio.h,stdlib.h,string.h,sys/ioctl.h,syslog.h,sys/resource.h,sys/socket.h,sys/stat.h,sys/time.h,sys/types.h,time.h,unistd.h,vpx/vp8cx.h,vpx/vp8dx.h,vpx/vpx_decoder.h,vpx/vpx_encoder.h,vpx/vpx_image.h" - key: hicpp-signed-bitwise.IgnorePositiveIntegerLiterals value: true - key: concurrency-mt-unsafe.FunctionSet value: posix - key: readability-function-cognitive-complexity.Threshold value: 153 # TODO(iphydf): Decrease. tox_new is the highest at the moment. - key: cppcoreguidelines-avoid-do-while.IgnoreMacros value: true - key: readability-simplify-boolean-expr.SimplifyDeMorgan value: false c-toxcore-0.2.20/.clusterfuzzlite/0000755060175106017510000000000014714247532015033 5ustar robinc-toxcore-0.2.20/.clusterfuzzlite/build.sh0000755060175106017510000000121214714247532016465 0ustar robin#!/bin/bash -eu FUZZ_TARGETS="bootstrap_fuzz_test toxsave_fuzz_test" # out of tree build cd "$WORK" ls /usr/local/lib/ # Debug build for asserts cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER="$CC" \ -DCMAKE_CXX_COMPILER="$CXX" \ -DCMAKE_C_FLAGS="$CFLAGS" \ -DCMAKE_CXX_FLAGS="$CXXFLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LIB_FUZZING_ENGINE" \ -DBUILD_TOXAV=OFF -DENABLE_SHARED=NO -DBUILD_FUZZ_TESTS=ON \ -DDHT_BOOTSTRAP=OFF -DBOOTSTRAP_DAEMON=OFF "$SRC"/c-toxcore for TARGET in $FUZZ_TARGETS; do # build fuzzer target cmake --build ./ --target "$TARGET" # copy to output files cp "$WORK/testing/fuzzing/$TARGET" "$OUT"/ done c-toxcore-0.2.20/.clusterfuzzlite/Dockerfile0000644060175106017510000000144314714247532017027 0ustar robin# c-toxcore Clusterfuzzlite build environment # We want to use the latest tools always FROM gcr.io/oss-fuzz-base/base-builder:latest RUN apt-get update && \ apt-get -y install --no-install-suggests --no-install-recommends \ cmake libtool autoconf automake pkg-config \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Static builds of dependencies # libsodium RUN git clone --depth 1 --branch 1.0.18 https://github.com/jedisct1/libsodium libsodium WORKDIR $SRC/libsodium RUN ./autogen.sh && ./configure --enable-shared=no && make install WORKDIR $SRC # Copy your project's source code. COPY . $SRC/c-toxcore # Working directory for build.sh. WORKDIR $SRC/c-toxcore RUN git submodule update --init --recursive # Copy build.sh into $SRC dir. COPY ./.clusterfuzzlite/build.sh $SRC/ c-toxcore-0.2.20/.devcontainer/0000755060175106017510000000000014714247532014236 5ustar robinc-toxcore-0.2.20/.devcontainer/devcontainer.json0000644060175106017510000000051414714247532017612 0ustar robin{ "image": "mcr.microsoft.com/devcontainers/universal:2", "features": { "ghcr.io/devcontainers-contrib/features/bash-command:1": { "command": "git submodule update --init --recursive" }, "ghcr.io/devcontainers-contrib/features/apt-packages:1": { "packages": "libconfig-dev,libopus-dev,libvpx-dev,ninja-build" } } } c-toxcore-0.2.20/.dockerignore0000644060175106017510000000002214714247532014145 0ustar robin/_build /_install c-toxcore-0.2.20/.editorconfig0000644060175106017510000000045514714247532014160 0ustar robinroot = true [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.{c,h}] indent_style = space indent_size = 4 [*.{yml,sh,cmake}] indent_style = space indent_size = 2 [Makefile] indent_style = tab indent_size = 4 [CMakeLists.txt] indent_style = space indent_size = 2 c-toxcore-0.2.20/.github/0000755060175106017510000000000014714247532013037 5ustar robinc-toxcore-0.2.20/.github/CODEOWNERS0000644060175106017510000000003114714247532014424 0ustar robin/.github/ @TokTok/admins c-toxcore-0.2.20/.github/dependabot.yml0000644060175106017510000000023314714247532015665 0ustar robin--- version: 2 updates: - package-ecosystem: gitsubmodule directory: "/" schedule: interval: daily time: "11:00" open-pull-requests-limit: 2 c-toxcore-0.2.20/.github/scripts/0000755060175106017510000000000014714247532014526 5ustar robinc-toxcore-0.2.20/.github/scripts/autotools-linux0000755060175106017510000000105714714247532017645 0ustar robin#!/bin/bash set -eu NPROC=$(nproc) . ".github/scripts/flags-$CC.sh" add_ld_flag -Wl,-z,defs # Make compilation error on a warning add_flag -Werror add_config_flag --disable-ipv6 add_config_flag --enable-daemon add_config_flag --with-log-level=TRACE autoreconf -fi mkdir -p _build cd _build # pushd ../configure "${CONFIG_FLAGS[@]}" || (cat config.log && false) make "-j$NPROC" -k CFLAGS="$C_FLAGS" LDFLAGS="$LD_FLAGS" make -j50 -k distcheck DISTCHECK_CONFIGURE_FLAGS="${CONFIG_FLAGS[*]}" || (cat tox-*/_build/build/test-suite.log && false) cd - # popd c-toxcore-0.2.20/.github/scripts/cmake-alpine-s390x0000755060175106017510000000310514714247532017665 0ustar robin#!/bin/bash # Copyright (C) 2018-2023 nurupo # Toxcore building set -eux cd .. # /work . cmake-alpine-run.sh # === Get VM ready to build the code === start_vm RUN apk add cmake g++ ninja mv c-toxcore / # Copy over toxcore code from host to qemu scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -P "$SSH_PORT" -r /c-toxcore root@localhost:~ cd /c-toxcore . ".github/scripts/flags-gcc.sh" # Make compilation error on a warning add_flag -Werror # - disabling toxav because vpx doesn't work on s390x. # - disabling bootstrap daemons because we don't need them for testing (saving time). # - disabling shared libraries because it saves a lot of time on building PIC objects. # - enable unity build because it saves a lot of time as well (fewer objects to build). RUN "cmake -B_build -Hc-toxcore -GNinja \ -DCMAKE_C_FLAGS='$C_FLAGS' \ -DCMAKE_CXX_FLAGS='$CXX_FLAGS' \ -DCMAKE_EXE_LINKER_FLAGS='$LD_FLAGS' \ -DCMAKE_SHARED_LINKER_FLAGS='$LD_FLAGS' \ -DCMAKE_INSTALL_PREFIX:PATH='_install' \ -DCMAKE_UNITY_BUILD=ON \ -DMIN_LOGGER_LEVEL=TRACE \ -DNON_HERMETIC_TESTS=ON \ -DENABLE_SHARED=OFF \ -DBUILD_TOXAV=OFF \ -DDHT_BOOTSTRAP=OFF \ -DBOOTSTRAP_DAEMON=OFF \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=90 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON" RUN 'cmake --build _build --parallel 2 --target install -- -k 0' RUN 'cd _build && ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:1 --timeout 90 || true' & # Give the tests 5 minutes to run. Sometimes, the per-test timeout doesn't # work, so we put a global timeout here for everything. sleep 300 c-toxcore-0.2.20/.github/scripts/cmake-android0000755060175106017510000000240414714247532017152 0ustar robin#!/bin/bash set -eu # Set up environment NDK=$ANDROID_NDK_HOME ABI=${1:-"armeabi-v7a"} case $ABI in armeabi-v7a) TARGET=armv7a-linux-androideabi NDK_API=21 ;; arm64-v8a) TARGET=aarch64-linux-android NDK_API=21 ;; x86) TARGET=i686-linux-android NDK_API=21 ;; x86_64) TARGET=x86_64-linux-android NDK_API=21 ;; *) exit 1 ;; esac rm -rf _android_prefix mkdir -p _android_prefix PREFIX=$PWD/_android_prefix TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64 SYSROOT=$TOOLCHAIN/sysroot export CC="$TOOLCHAIN/bin/$TARGET$NDK_API"-clang export LDFLAGS=-static-libstdc++ export PKG_CONFIG_PATH="$PREFIX"/lib/pkgconfig # Build libsodium if [ ! -d libsodium ]; then git clone --branch=1.0.18 https://github.com/jedisct1/libsodium.git fi cd libsodium git clean -ffdx autoreconf -fi ./configure --prefix="$PREFIX" --host="$TARGET" --with-sysroot="$SYSROOT" --disable-shared --disable-pie make -j"$(nproc)" install cd .. # Build c-toxcore rm -rf _build mkdir -p _build cd _build cmake .. \ -DBUILD_TOXAV=OFF \ -DBOOTSTRAP_DAEMON=OFF \ -DCMAKE_TOOLCHAIN_FILE="$NDK/build/cmake/android.toolchain.cmake" \ -DANDROID_ABI="$ABI" \ -DCMAKE_INSTALL_PREFIX="$PREFIX" \ -DCMAKE_PREFIX_PATH="$PREFIX" cmake --build . c-toxcore-0.2.20/.github/scripts/cmake-freebsd0000755060175106017510000000256214714247532017151 0ustar robin#!/bin/bash # Copyright (C) 2018-2023 nurupo # Toxcore building set -eux cd .. # /work . cmake-freebsd-run.sh # === Get VM ready to build the code === # Unpack image only if it's compressed. if [ -f "$IMAGE_NAME.gz" ]; then gunzip "$IMAGE_NAME.gz" fi mv c-toxcore / start_vm # Copy over toxcore code from host to qemu scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -P "$SSH_PORT" -r /c-toxcore root@localhost:~ RUN ls -lh cd /c-toxcore . '.github/scripts/flags-clang.sh' add_ld_flag -Wl,-z,defs # Make compilation error on a warning. add_flag -Werror # This triggers on FreeBSD's clang. add_flag -Wno-format add_flag -Wno-unsafe-buffer-usage RUN "cmake -B_build -Hc-toxcore \ -DCMAKE_C_FLAGS='$C_FLAGS' \ -DCMAKE_CXX_FLAGS='$CXX_FLAGS' \ -DCMAKE_EXE_LINKER_FLAGS='$LD_FLAGS' \ -DCMAKE_SHARED_LINKER_FLAGS='$LD_FLAGS' \ -DCMAKE_INSTALL_PREFIX:PATH='_install' \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON" # We created the VM with the same number of cores as the host, so the host-ran `nproc` here is fine. RUN 'cmake --build _build --parallel "$NPROC" --target install -- -k' RUN 'cd _build && ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:2 --timeout 120 || true' # Gracefully shut down the VM. stop_vm c-toxcore-0.2.20/.github/scripts/cmake-osx0000755060175106017510000000212714714247532016345 0ustar robin#!/bin/bash set -eu NPROC=$(sysctl -n hw.physicalcpu) # Workaround for bug in Homebrew where it only finds an old Ruby version. brew update brew install \ libconfig \ libsodium \ libvpx \ opus . ".github/scripts/flags-clang.sh" add_ld_flag -undefined error # Make compilation error on a warning add_flag -Werror # Allow _Static_assert. Supported C11 extensions are fine, since we have several # C99-only compilers we test against anyway. Anything that passes all the # compilers we use is fine. add_c_flag -Wno-c11-extensions cmake -B_build -H. \ -DCMAKE_C_FLAGS="$C_FLAGS" \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_INSTALL_PREFIX:PATH="$PWD/_install" \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cd _build # pushd make "-j$NPROC" -k install ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 || ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 cd - # popd c-toxcore-0.2.20/.github/scripts/cmake-win320000755060175106017510000000014314714247532016472 0ustar robin#!/usr/bin/env bash i686=true x86_64=false WINDOWS_ARCH=win32 . .github/scripts/cmake-windows.sh c-toxcore-0.2.20/.github/scripts/cmake-win640000755060175106017510000000014314714247532016477 0ustar robin#!/usr/bin/env bash i686=false x86_64=true WINDOWS_ARCH=win64 . .github/scripts/cmake-windows.sh c-toxcore-0.2.20/.github/scripts/cmake-windows.sh0000755060175106017510000000145614714247532017643 0ustar robin#!/bin/bash set -eu NPROC=$(nproc) . ".github/scripts/flags-gcc.sh" # Allows wine to display source code file names and line numbers on crash in # its backtrace. add_flag -gdwarf-2 # Fix invalid register for .seh_savexmm error add_flag -fno-asynchronous-unwind-tables docker run \ -e ALLOW_TEST_FAILURE=true \ -e ENABLE_ARCH_i686="$i686" \ -e ENABLE_ARCH_x86_64="$x86_64" \ -e ENABLE_TEST=true \ -e EXTRA_CMAKE_FLAGS="-DBOOTSTRAP_DAEMON=OFF -DMIN_LOGGER_LEVEL=DEBUG -DTEST_TIMEOUT_SECONDS=90 -DAUTOTEST=ON -DUSE_IPV6=OFF" \ -e CMAKE_C_FLAGS="$C_FLAGS" \ -e CMAKE_CXX_FLAGS="$CXX_FLAGS" \ -e CMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -e CMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -v "$PWD:/toxcore" \ -v "$PWD/result:/prefix" \ --rm \ -t \ --pull never \ "toxchat/windows:$WINDOWS_ARCH" c-toxcore-0.2.20/.github/scripts/flags-clang.sh0000755060175106017510000000561414714247532017251 0ustar robin#!/bin/bash . .github/scripts/flags.sh # Add all warning flags we can. add_flag -Wall add_flag -Wextra add_flag -Weverything # Disable specific warning flags for both C and C++. # Very verbose, not very useful. This warns about things like int -> uint # conversions that change sign without a cast and narrowing conversions. add_flag -Wno-conversion # TODO(iphydf): Check enum values when received from the user, then assume # correctness and remove this suppression. add_flag -Wno-covered-switch-default # We use C99, so declarations can come after statements. add_flag -Wno-declaration-after-statement # Due to clang's tolower() macro being recursive # https://github.com/TokTok/c-toxcore/pull/481 add_flag -Wno-disabled-macro-expansion # We don't put __attribute__ on the public API. add_flag -Wno-documentation-deprecated-sync # Bootstrap daemon does this. add_flag -Wno-format-nonliteral # struct Foo foo = {0}; is a common idiom. Missing braces means we'd need to # write {{{0}}} in some cases, which is ugly and a maintenance burden. add_flag -Wno-missing-braces add_flag -Wno-missing-field-initializers # We don't use this attribute. It appears in the non-NDEBUG stderr logger. add_flag -Wno-missing-noreturn # Useful sometimes, but we accept padding in structs for clarity. # Reordering fields to avoid padding will reduce readability. add_flag -Wno-padded # This warns on things like _XOPEN_SOURCE, which we currently need (we # probably won't need these in the future). add_flag -Wno-reserved-id-macro # We don't want to have default cases, we want to explicitly define all cases add_flag -Wno-switch-default # __attribute__((nonnull)) causes this warning on defensive null checks. add_flag -Wno-tautological-pointer-compare # Our use of mutexes results in a false positive, see 1bbe446. add_flag -Wno-thread-safety-analysis # File transfer code has this. add_flag -Wno-type-limits # Generates false positives in toxcore similar to # https://github.com/llvm/llvm-project/issues/64646 add_flag -Wno-unsafe-buffer-usage # Callbacks often don't use all their parameters. add_flag -Wno-unused-parameter # cimple does this better add_flag -Wno-unused-function # libvpx uses __attribute__((unused)) for "potentially unused" static # functions to avoid unused static function warnings. add_flag -Wno-used-but-marked-unused # We use variable length arrays a lot. add_flag -Wno-vla # Disable warnings about unknown Doxygen commands add_flag -Wno-documentation-unknown-command # Disable specific warning flags for C++. # Comma at end of enum is supported everywhere we run. add_cxx_flag -Wno-c++98-compat-pedantic # TODO(iphydf): Stop using flexible array members. add_cxx_flag -Wno-c99-extensions # We're C-compatible, so use C style casts. add_cxx_flag -Wno-old-style-cast # GTest does this. add_cxx_flag -Wno-global-constructors # Downgrade to warning so we still see it. add_flag -Wno-error=unreachable-code add_flag -Wno-error=unused-variable c-toxcore-0.2.20/.github/scripts/flags-coverage.sh0000755060175106017510000000155314714247532017756 0ustar robin#!/bin/bash . .github/scripts/flags-clang.sh add_ld_flag -Wl,-z,defs # Make compilation error on a warning add_flag -Werror -Wno-unsafe-buffer-usage # Coverage flags. add_flag -fprofile-instr-generate -fcoverage-mapping # Optimisation, but keep stack traces useful. add_c_flag -fno-inline -fno-omit-frame-pointer # Show useful stack traces on crash. add_flag -fsanitize=undefined -fno-sanitize-recover=all -D_DEBUG # In test code (_test.cc and libgtest), throw away all debug information. # We only care about stack frames inside toxcore (which is C). Without this, # mallocfail will spend a lot of time finding all the ways in which gtest can # fail to allocate memory, which is not interesting to us. add_cxx_flag -g0 # Continue executing code in error paths so we can see it cleanly exit (and the # test code itself may abort). add_flag -DABORT_ON_LOG_ERROR=false c-toxcore-0.2.20/.github/scripts/flags-gcc.sh0000755060175106017510000000341414714247532016715 0ustar robin#!/bin/bash . .github/scripts/flags.sh # Add all warning flags we can. add_flag -Wall add_flag -Wextra # Some additional warning flags not enabled by any of the above. add_flag -Wbool-compare add_flag -Wcast-align add_flag -Wcast-qual add_flag -Wchar-subscripts add_flag -Wdouble-promotion add_flag -Wduplicated-cond add_flag -Wempty-body add_flag -Wenum-compare add_flag -Wfloat-equal add_flag -Wformat=2 add_flag -Wframe-address add_flag -Wframe-larger-than=9000 add_flag -Wignored-attributes add_flag -Wignored-qualifiers add_flag -Winit-self add_flag -Winline add_flag -Wlarger-than=530000 add_flag -Wmaybe-uninitialized add_flag -Wmemset-transposed-args add_flag -Wmisleading-indentation add_flag -Wmissing-declarations add_flag -Wnonnull add_flag -Wnull-dereference add_flag -Wodr add_flag -Wredundant-decls add_flag -Wreturn-type add_flag -Wshadow add_flag -Wsuggest-attribute=format add_flag -Wundef add_flag -Wunsafe-loop-optimizations add_flag -Wunused-but-set-parameter add_flag -Wunused-but-set-variable add_flag -Wunused-label add_flag -Wunused-local-typedefs add_flag -Wunused-value # Disable specific warning flags for both C and C++. # struct Foo foo = {0}; is a common idiom. add_flag -Wno-missing-field-initializers # Checked by clang, but gcc is warning when it's not necessary. add_flag -Wno-sign-compare # File transfer code has this. add_flag -Wno-type-limits # Callbacks often don't use all their parameters. add_flag -Wno-unused-parameter # cimple does this better add_flag -Wno-unused-function # struct Foo foo = {0}; is a common idiom. Missing braces means we'd need to # write {{{0}}} in some cases, which is ugly and a maintenance burden. add_flag -Wno-missing-braces # __attribute__((nonnull)) causes this warning on defensive null checks. add_flag -Wno-nonnull-compare c-toxcore-0.2.20/.github/scripts/flags.sh0000755060175106017510000000135014714247532016160 0ustar robin#!/bin/bash add_config_flag() { CONFIG_FLAGS+=("$@"); } add_c_flag() { C_FLAGS="$C_FLAGS $@"; } add_cxx_flag() { CXX_FLAGS="$CXX_FLAGS $@"; } add_ld_flag() { LD_FLAGS="$LD_FLAGS $@"; } add_flag() { add_c_flag "$@" add_cxx_flag "$@" } # Our own flags which we can insert in the correct place. We don't use CFLAGS # and friends here (we unset them below), because they influence config tests # such as ./configure and cmake tests. Our warning flags break those tests, so # we can't add them globally here. CONFIG_FLAGS=() C_FLAGS="" CXX_FLAGS="" LD_FLAGS="" unset CFLAGS unset CXXFLAGS unset CPPFLAGS unset LDFLAGS # Optimisation flags. add_flag -O3 -march=native # Warn on non-ISO C. add_c_flag -pedantic add_flag -g3 add_flag -ftrapv c-toxcore-0.2.20/.github/scripts/sonar-build0000755060175106017510000000017414714247532016675 0ustar robin#!/bin/bash set -eu . ".github/scripts/flags-gcc.sh" cmake --build _build --parallel "$(nproc)" --target install -- -k 0 c-toxcore-0.2.20/.github/scripts/sonar-prepare0000755060175106017510000000126314714247532017234 0ustar robin#!/bin/bash set -eu sudo apt-get install -y --no-install-recommends \ libconfig-dev \ libopus-dev \ libsodium-dev \ libvpx-dev \ ninja-build . ".github/scripts/flags-gcc.sh" add_ld_flag -Wl,-z,defs # Make compilation error on a warning add_flag -Werror cmake -B_build -H. -GNinja \ -DCMAKE_C_FLAGS="$C_FLAGS" \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_SHARED_LINKER_FLAGS="$LD_FLAGS" \ -DCMAKE_INSTALL_PREFIX:PATH="$PWD/_install" \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=OFF \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON \ -DENABLE_SHARED=OFF c-toxcore-0.2.20/.github/scripts/tox-bootstrapd-docker0000755060175106017510000000417414714247532020720 0ustar robin#!/bin/bash set -exu -o pipefail LOCAL="${1:-}" CHECK="${2:-}" readarray -t FILES <<<"$(git ls-files)" if ! tar c "${FILES[@]}" | docker build --build-arg="CHECK=$CHECK" -f other/bootstrap_daemon/docker/Dockerfile -t toxchat/bootstrap-node - 2>&1 | tee docker-build.log; then grep -o "::error.*::[a-f0-9]* /usr/local/bin/tox-bootstrapd" docker-build.log false fi docker tag toxchat/bootstrap-node:latest toxchat/bootstrap-node:"$(other/print-version)" sudo useradd \ --home-dir /var/lib/tox-bootstrapd \ --create-home \ --system \ --shell /sbin/nologin \ --comment "Account to run Tox's DHT bootstrap daemon" \ --user-group tox-bootstrapd sudo chmod 700 /var/lib/tox-bootstrapd docker run -d --name tox-bootstrapd \ --user "$(id -u tox-bootstrapd):$(id -g tox-bootstrapd)" \ -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ \ --ulimit nofile=32768:32768 \ -p 443:443 \ -p 3389:3389 \ -p 33445:33445 \ -p 33445:33445/udp \ toxchat/bootstrap-node sudo ls -lbh /var/lib/tox-bootstrapd if sudo [ ! -f /var/lib/tox-bootstrapd/keys ]; then echo "Error: File /var/lib/tox-bootstrapd/keys doesn't exist" exit 1 fi if [ "$LOCAL" != "local" ]; then COUNTER=0 COUNTER_END=120 while [ "$COUNTER" -lt "$COUNTER_END" ]; do if docker logs tox-bootstrapd | grep -q "Connected to another bootstrap node successfully"; then break fi sleep 1 COUNTER=$(($COUNTER + 1)) done docker logs tox-bootstrapd if [ "$COUNTER" = "$COUNTER_END" ]; then echo "Error: Didn't connect to any nodes" exit 1 fi else docker logs tox-bootstrapd fi # Wait a bit before testing if the container is still running sleep 30 docker ps -a if [ "$(docker inspect -f {{.State.Running}} tox-bootstrapd)" != "true" ]; then echo "Error: Container is not running" exit 1 fi cat /proc/"$(pidof tox-bootstrapd)"/limits if ! grep -P '^Max open files(\s+)32768(\s+)32768(\s+)files' /proc/"$(pidof tox-bootstrapd)"/limits; then echo "Error: ulimit is not set to the expected value" exit 1 fi if ! other/fun/bootstrap_node_info.py ipv4 localhost 33445; then echo "Error: Unable to get bootstrap node info" exit 1 fi c-toxcore-0.2.20/.github/workflows/0000755060175106017510000000000014714247532015074 5ustar robinc-toxcore-0.2.20/.github/workflows/cflite_batch.yml0000644060175106017510000000247214714247532020233 0ustar robin# Derived from: https://google.github.io/clusterfuzzlite/running-clusterfuzzlite/github-actions/ name: ClusterFuzzLite batch fuzzing on: schedule: - cron: '0 6,8 * * *' # Run twice a day at low activity times workflow_dispatch: # Manual trigger for testing permissions: read-all jobs: BatchFuzzing: runs-on: ubuntu-latest strategy: fail-fast: false matrix: sanitizer: - address - undefined - memory steps: - name: Build Fuzzers (${{ matrix.sanitizer }}) id: build uses: google/clusterfuzzlite/actions/build_fuzzers@v1 with: sanitizer: ${{ matrix.sanitizer }} - name: Run Fuzzers (${{ matrix.sanitizer }}) id: run uses: google/clusterfuzzlite/actions/run_fuzzers@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} fuzz-seconds: 3600 # 60min mode: 'batch' sanitizer: ${{ matrix.sanitizer }} # Optional but recommended: For storing certain artifacts from fuzzing. # See later section on "Git repo for storage". storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/TokTok/toktok-fuzzer.git storage-repo-branch: master # Optional. Defaults to "main" storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". c-toxcore-0.2.20/.github/workflows/cflite_cron.yml0000644060175106017510000000335414714247532020113 0ustar robin# Derived from: https://google.github.io/clusterfuzzlite/running-clusterfuzzlite/github-actions/ name: ClusterFuzzLite cron tasks on: schedule: - cron: '0 10 * * *' # Once a day, after fuzzing run workflow_dispatch: # Manual trigger for testing permissions: read-all jobs: Pruning: runs-on: ubuntu-latest steps: - name: Build Fuzzers id: build uses: google/clusterfuzzlite/actions/build_fuzzers@v1 - name: Run Fuzzers id: run uses: google/clusterfuzzlite/actions/run_fuzzers@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} fuzz-seconds: 600 mode: 'prune' # Optional but recommended. # See later section on "Git repo for storage". storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/TokTok/toktok-fuzzer.git storage-repo-branch: master # Optional. Defaults to "main" storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". Coverage: runs-on: ubuntu-latest steps: - name: Build Fuzzers id: build uses: google/clusterfuzzlite/actions/build_fuzzers@v1 with: sanitizer: coverage - name: Run Fuzzers id: run uses: google/clusterfuzzlite/actions/run_fuzzers@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} fuzz-seconds: 600 mode: 'coverage' sanitizer: 'coverage' # Optional but recommended. # See later section on "Git repo for storage". storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/TokTok/toktok-fuzzer.git storage-repo-branch: master # Optional. Defaults to "main" storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". c-toxcore-0.2.20/.github/workflows/ci.yml0000644060175106017510000001327314714247532016220 0ustar robinname: ci on: pull_request: branches: [master] # Cancel old PR builds when pushing new commits. concurrency: group: build-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: common: uses: TokTok/ci-tools/.github/workflows/common-ci.yml@master analysis: strategy: fail-fast: false matrix: tool: [autotools, clang-tidy, compcert, cppcheck, doxygen, goblint, infer, freebsd, misra, modules, pkgsrc, rpm, slimcc, sparse, tcc, tokstyle] runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: driver: docker - name: Build toxchat/c-toxcore:sources uses: docker/build-push-action@v5 with: file: other/docker/sources/sources.Dockerfile tags: toxchat/c-toxcore:sources - name: Docker Build uses: docker/build-push-action@v5 with: file: other/docker/${{ matrix.tool }}/${{ matrix.tool }}.Dockerfile coverage-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Build, test, and upload coverage run: other/docker/coverage/run generate-events: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Run generate_event_c run: | other/event_tooling/run git diff --exit-code cimplefmt: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Run cimplefmt run: other/docker/cimplefmt/run -u $(find tox* -name "*.[ch]") build-android: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - run: .github/scripts/cmake-android armeabi-v7a - run: .github/scripts/cmake-android arm64-v8a - run: .github/scripts/cmake-android x86 - run: .github/scripts/cmake-android x86_64 build-macos: runs-on: macos-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Build and test run: .github/scripts/cmake-osx build-windows-msvc: strategy: matrix: version: [2019, 2022] runs-on: windows-${{ matrix.version }} env: VCPKG_ROOT: "C:/vcpkg" VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Export GitHub Actions cache environment variables uses: actions/github-script@v7 with: script: | core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - name: Configure CMake run: cmake --preset windows-default - name: Build run: cmake --build _build -j $([int]$env:NUMBER_OF_PROCESSORS+2) - name: Test run: | cd _build ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 --build-config Debug build-netbsd: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Test in NetBSD id: test uses: vmactions/netbsd-vm@v1 with: usesh: true copyback: false prepare: /usr/sbin/pkg_add cmake googletest libconfig libopus libsodium libvpx pkg-config run: | # TODO(iphydf): Investigate NetBSD failures on these tests. sed -Ei -e '/\((TCP|dht_getnodes_api)\)/s/^/#/' auto_tests/CMakeLists.txt cmake . \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DTEST_TIMEOUT_SECONDS=90 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cmake --build . --target install ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 build-freebsd: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Test in FreeBSD id: test uses: vmactions/freebsd-vm@v1 with: usesh: true copyback: false prepare: PAGER=cat ASSUME_ALWAYS_YES=YES pkg install cmake git gmake googletest libconfig libsodium libvpx opus pkgconf run: | # TODO(iphydf): Investigate FreeBSD failures on these tests. sed -Ei -e '/\(dht_getnodes_api\)/s/^/#/' auto_tests/CMakeLists.txt cmake . \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ -DNON_HERMETIC_TESTS=ON \ -DTEST_TIMEOUT_SECONDS=50 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON cmake --build . --target install ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 mypy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Python 3.9 uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install mypy run: pip install mypy - name: Run mypy run: | (find . -name "*.py" -and -not -name "conanfile.py"; grep -lR '^#!.*python') \ | xargs -n1 -P8 mypy --strict c-toxcore-0.2.20/.github/workflows/coverity-scan.yml0000644060175106017510000000302214714247532020402 0ustar robinname: coverity-scan on: schedule: - cron: '0 10 * * *' # Once a day jobs: latest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install libraries run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libopus-dev libsodium-dev libvpx-dev - name: Download Coverity Build Tool run: | wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=TokTok/c-toxcore" -O cov-analysis-linux64.tar.gz mkdir cov-analysis-linux64 tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 env: TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} - name: Run autoreconf run: autoreconf -fi - name: Configure run: ./configure - name: Build with cov-build run: cov-analysis-linux64/bin/cov-build --dir cov-int make - name: Submit the result to Coverity Scan run: tar czvf c-toxcore.tgz cov-int && curl --form project=TokTok/c-toxcore --form token=$TOKEN --form email=iphydf@gmail.com --form file=@c-toxcore.tgz --form version="$(git rev-list --count HEAD)" --form description="CI build of $(git rev-parse --abbrev-ref HEAD) branch" https://scan.coverity.com/builds env: TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} c-toxcore-0.2.20/.github/workflows/docker.yml0000644060175106017510000001433414714247532017073 0ustar robinname: docker on: push: branches: [master] pull_request: branches: [master] # Cancel old PR builds when pushing new commits. concurrency: group: docker-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: docker-bootstrap-node: runs-on: ubuntu-latest steps: - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - uses: actions/checkout@v4 with: submodules: recursive - name: Docker Build run: .github/scripts/tox-bootstrapd-docker local "$CHECK" env: CHECK: "${{ contains(github.event.pull_request.title, 'chore: Release ') && 'sha256sum' || 'echo' }}" - name: Push latest image to DockerHub if: ${{ github.event_name == 'push' }} run: docker push toxchat/bootstrap-node:latest - name: Push versioned image to DockerHub if: ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }} run: docker push toxchat/bootstrap-node:"$(other/print-version)" docker-bootstrap-node-websocket: runs-on: ubuntu-latest needs: [docker-bootstrap-node] steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: context: "{{defaultContext}}:other/bootstrap_daemon/websocket" push: ${{ github.event_name == 'push' }} tags: toxchat/bootstrap-node:latest-websocket cache-from: type=registry,ref=toxchat/bootstrap-node:latest-websocket cache-to: type=inline docker-clusterfuzz: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: context: "." file: .clusterfuzzlite/Dockerfile push: ${{ github.event_name == 'push' }} tags: toxchat/c-toxcore:clusterfuzz cache-from: type=registry,ref=toxchat/c-toxcore:clusterfuzz cache-to: type=inline docker-fuzzer: runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: file: testing/Dockerfile push: ${{ github.event_name == 'push' }} tags: toxchat/c-toxcore:fuzzer cache-from: type=registry,ref=toxchat/c-toxcore:fuzzer cache-to: type=inline docker-toxcore-js: runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: file: other/emscripten/Dockerfile push: ${{ github.event_name == 'push' }} tags: toxchat/c-toxcore:wasm cache-from: type=registry,ref=toxchat/c-toxcore:wasm cache-to: type=inline docker-esp32: runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: file: other/docker/esp32/Dockerfile push: ${{ github.event_name == 'push' }} tags: toxchat/c-toxcore:esp32 cache-from: type=registry,ref=toxchat/c-toxcore:esp32 cache-to: type=inline docker-windows-mingw: strategy: matrix: bits: [32, 64] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and store to local Docker daemon uses: docker/build-push-action@v5 with: context: other/docker/windows load: true tags: toxchat/windows:win${{ matrix.bits }} cache-from: type=registry,ref=toxchat/windows:win${{ matrix.bits }} build-args: | SUPPORT_ARCH_i686=${{ matrix.bits == '32' }} SUPPORT_ARCH_x86_64=${{ matrix.bits == '64' }} SUPPORT_TEST=true - name: Push the stored image to Dockerhub if: ${{ github.event_name == 'push' }} uses: docker/build-push-action@v5 with: context: other/docker/windows push: ${{ github.event_name == 'push' }} tags: toxchat/windows:win${{ matrix.bits }} build-args: | SUPPORT_ARCH_i686=${{ matrix.bits == '32' }} SUPPORT_ARCH_x86_64=${{ matrix.bits == '64' }} SUPPORT_TEST=true - name: Cross-compile run: .github/scripts/cmake-win${{ matrix.bits }} script c-toxcore-0.2.20/.github/workflows/post-submit.yml0000644060175106017510000000240414714247532020105 0ustar robinname: post-submit on: push: branches: [master] jobs: build-alpine-s390x: runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Docker Build uses: docker/build-push-action@v5 with: file: other/docker/alpine-s390x/Dockerfile docker-coverage: runs-on: ubuntu-latest steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: driver: docker - name: Login to DockerHub if: ${{ github.event_name == 'push' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build toxchat/c-toxcore:sources uses: docker/build-push-action@v5 with: file: other/docker/sources/sources.Dockerfile tags: toxchat/c-toxcore:sources - name: Build and push uses: docker/build-push-action@v5 with: file: other/docker/coverage/coverage.Dockerfile push: ${{ github.event_name == 'push' }} tags: toxchat/c-toxcore:coverage cache-from: type=registry,ref=toxchat/c-toxcore:coverage cache-to: type=inline c-toxcore-0.2.20/.github/workflows/release.yml0000644060175106017510000000034414714247532017240 0ustar robinname: release on: push: branches: [master] pull_request_target: branches: [master] types: [opened, reopened, synchronize] jobs: release: uses: TokTok/ci-tools/.github/workflows/release-drafter.yml@master c-toxcore-0.2.20/.github/workflows/sonar-scan.yml0000644060175106017510000000454414714247532017672 0ustar robinname: sonar-scan on: push: branches: [master] pull_request: branches: [master] # Cancel old PR builds when pushing new commits. concurrency: group: scan-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: sonar-scan: runs-on: ubuntu-latest env: SONAR_SCANNER_VERSION: 5.0.1.3006 SONAR_SERVER_URL: "https://sonarcloud.io" BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis submodules: recursive - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: "zulu" java-version: 17 - name: Download and set up sonar-scanner env: SONAR_SCANNER_DOWNLOAD_URL: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux.zip run: | mkdir -p $HOME/.sonar curl -sSLo $HOME/.sonar/sonar-scanner.zip ${{ env.SONAR_SCANNER_DOWNLOAD_URL }} unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ echo "$HOME/.sonar/sonar-scanner-${{ env.SONAR_SCANNER_VERSION }}-linux/bin" >> $GITHUB_PATH - name: Download and set up build-wrapper env: BUILD_WRAPPER_DOWNLOAD_URL: ${{ env.SONAR_SERVER_URL }}/static/cpp/build-wrapper-linux-x86.zip run: | curl -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip ${{ env.BUILD_WRAPPER_DOWNLOAD_URL }} unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/ echo "$HOME/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH - name: Install dependencies and prepare build run: | .github/scripts/sonar-prepare - name: Run build-wrapper run: | build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} .github/scripts/sonar-build - name: Run sonar-scanner if: github.event_name == 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: 'sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}"' c-toxcore-0.2.20/.gitignore0000644060175106017510000000162314714247532013471 0ustar robin# OS files .DS_Store .DS_Store? ._* .mypy_cache .Spotlight-V100 .Trash* Icon? ethumbs.db Thumbs.db *.tmp # Make /_build /_install /tox-0.0.0* /.vs /CppProperties.json CMakeCache.txt CMakeFiles Makefile !/other/rpm/Makefile cmake_install.cmake install_manifest.txt tags Makefile.in CMakeLists.txt.user DartConfiguration.tcl CTestTestfile.cmake *.pc # Testing /amalgamation.* testing/data *~ # Vim *.swp # Object files *.o *.lo *.a # Executables *.exe *.out *.app *.la # Libraries *.so # Misc (?) m4/* configure configure_aux !m4/pkg.m4 aclocal.m4 config.h* config.log config.status stamp-h1 autom4te.cache libtool .deps .libs .dirstamp build/ *.nvim* *.vim* # kdevelop .kdev/ *.kdev* # VScode .vscode/ # Netbeans nbproject # astyle *.orig # Android buildscript android-toolchain-* toxcore-android-* # cscope files list cscope.files # rpm tox.spec # clangd .cache/ compile_commands.json /infer .idea/ c-toxcore-0.2.20/.gitmodules0000644060175106017510000000013314714247532013651 0ustar robin[submodule "third_party/cmp"] path = third_party/cmp url = https://github.com/TokTok/cmp c-toxcore-0.2.20/.hadolint.yaml0000644060175106017510000000047214714247532014246 0ustar robin--- ignored: # "cd" is sometimes useful when you want to run one command in one directory # and then another command in another directory, but they should be executed # in the same RUN instruction. - DL3003 - DL3007 - DL3008 - DL3013 - DL3018 - DL3059 # $(pkg-config ...) needs this - SC2046 c-toxcore-0.2.20/.restyled.yaml0000644060175106017510000000111014714247532014265 0ustar robin--- exclude: # shfmt doesn't support this file. - "other/analysis/run-clang-tidy" # Generated file. - "CHANGELOG.md" restylers: - astyle: image: restyled/restyler-astyle:d7967bcb8b622a98524b7df1da1b02652114cf9a arguments: ["--options=other/astyle/astylerc"] include: - "**/*.c" - "**/*.h" - autopep8 - black - clang-format: image: restyled/restyler-clang-format:v16.0.6 include: - "**/*.cc" - "**/*.hh" - prettier-markdown - prettier-yaml - reorder-python-imports - shellharden - shfmt - yapf c-toxcore-0.2.20/autogen.sh0000755060175106017510000000010414714247532013473 0ustar robin#!/bin/sh -e echo 'Running autoreconf -if...' ( autoreconf -if ) c-toxcore-0.2.20/auto_tests/0000755060175106017510000000000014714247532013671 5ustar robinc-toxcore-0.2.20/auto_tests/announce_test.c0000644060175106017510000001051414714247532016703 0ustar robin#include #include #include "../toxcore/announce.h" #include "../toxcore/tox.h" #include "../testing/misc_tools.h" #include "../toxcore/mono_time.h" #include "../toxcore/forwarding.h" #include "../toxcore/net_crypto.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" static void test_bucketnum(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t key1[CRYPTO_PUBLIC_KEY_SIZE], key2[CRYPTO_PUBLIC_KEY_SIZE]; random_bytes(rng, key1, sizeof(key1)); memcpy(key2, key1, CRYPTO_PUBLIC_KEY_SIZE); ck_assert_msg(announce_get_bucketnum(key1, key2) == 0, "Bad bucketnum"); key2[4] ^= 0x09; key2[5] ^= 0xc5; ck_assert_msg(announce_get_bucketnum(key1, key2) == 7, "Bad bucketnum"); key2[4] ^= 0x09; ck_assert_msg(announce_get_bucketnum(key1, key2) == 17, "Bad bucketnum"); key2[5] ^= 0xc5; key2[31] ^= 0x09; ck_assert_msg(announce_get_bucketnum(key1, key2) == 4, "Bad bucketnum"); } typedef struct Announce_Test_Data { uint8_t data[MAX_ANNOUNCEMENT_SIZE]; uint16_t length; bool passed; } Announce_Test_Data; static void test_announce_data(void *object, const uint8_t *data, uint16_t length) { Announce_Test_Data *test_data = (Announce_Test_Data *) object; test_data->passed = test_data->length == length && memcmp(test_data->data, data, length) == 0; } static void test_store_data(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Logger *log = logger_new(); ck_assert(log != nullptr); logger_callback_log(log, print_debug_logger, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); ck_assert(mono_time != nullptr); Networking_Core *net = new_networking_no_udp(log, mem, ns); ck_assert(net != nullptr); DHT *dht = new_dht(log, mem, rng, ns, mono_time, net, true, true); ck_assert(dht != nullptr); Forwarding *forwarding = new_forwarding(log, rng, mono_time, dht); ck_assert(forwarding != nullptr); Announcements *announce = new_announcements(log, mem, rng, mono_time, forwarding); ck_assert(announce != nullptr); /* Just to prevent CI from complaining that set_synch_offset is unused: */ announce_set_synch_offset(announce, 0); Announce_Test_Data test_data; random_bytes(rng, test_data.data, sizeof(test_data.data)); test_data.length = sizeof(test_data.data); uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]; random_bytes(rng, key, sizeof(key)); ck_assert_msg(!announce_on_stored(announce, key, nullptr, nullptr), "Unstored announcement exists"); ck_assert_msg(announce_store_data(announce, key, test_data.data, sizeof(test_data.data), MAX_MAX_ANNOUNCEMENT_TIMEOUT), "Failed to store announcement"); ck_assert_msg(announce_on_stored(announce, key, test_announce_data, &test_data), "Failed to get stored announcement"); ck_assert_msg(test_data.passed, "Bad stored announcement data"); const uint8_t *const base = dht_get_self_public_key(dht); ck_assert_msg(announce_store_data(announce, base, test_data.data, sizeof(test_data.data), 1), "failed to store base"); uint8_t test_keys[ANNOUNCE_BUCKET_SIZE + 1][CRYPTO_PUBLIC_KEY_SIZE]; for (uint8_t i = 0; i < ANNOUNCE_BUCKET_SIZE + 1; ++i) { memcpy(test_keys[i], base, CRYPTO_PUBLIC_KEY_SIZE); test_keys[i][i] ^= 1; ck_assert_msg(announce_store_data(announce, test_keys[i], test_data.data, sizeof(test_data.data), 1), "Failed to store announcement %d", i); } ck_assert_msg(announce_on_stored(announce, base, nullptr, nullptr), "base was evicted"); ck_assert_msg(!announce_on_stored(announce, test_keys[0], nullptr, nullptr), "furthest was not evicted"); ck_assert_msg(!announce_store_data(announce, test_keys[0], nullptr, 0, 1), "furthest evicted closer"); kill_announcements(announce); kill_forwarding(forwarding); kill_dht(dht); kill_networking(net); mono_time_free(mem, mono_time); logger_kill(log); } static void basic_announce_tests(void) { test_bucketnum(); test_store_data(); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); basic_announce_tests(); return 0; } c-toxcore-0.2.20/auto_tests/auto_test_support.c0000644060175106017510000003611414714247532017645 0ustar robin#include // assert #include // calloc, free #include "check_compat.h" #include "../testing/misc_tools.h" #include "../toxcore/Messenger.h" #include "../toxcore/mono_time.h" #include "../toxcore/tox_dispatch.h" #include "../toxcore/tox_events.h" #include "../toxcore/tox_struct.h" #include "auto_test_support.h" #ifndef ABORT_ON_LOG_ERROR #define ABORT_ON_LOG_ERROR true #endif #ifndef USE_IPV6 #define USE_IPV6 1 #endif Run_Auto_Options default_run_auto_options(void) { return (Run_Auto_Options) { .graph = GRAPH_COMPLETE, .init_autotox = nullptr, .tcp_port = 33188, .events = true, }; } // List of live bootstrap nodes. These nodes should have TCP server enabled. static const struct BootstrapNodes { const char *ip; uint16_t port; const uint8_t key[32]; } bootstrap_nodes[] = { { "tox.abilinski.com", 33445, 0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E, 0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5, 0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92, 0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E, }, { "tox.initramfs.io", 33445, 0x02, 0x80, 0x7C, 0xF4, 0xF8, 0xBB, 0x8F, 0xB3, 0x90, 0xCC, 0x37, 0x94, 0xBD, 0xF1, 0xE8, 0x44, 0x9E, 0x9A, 0x83, 0x92, 0xC5, 0xD3, 0xF2, 0x20, 0x00, 0x19, 0xDA, 0x9F, 0x1E, 0x81, 0x2E, 0x46, }, { "tox.plastiras.org", 33445, 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25, }, { "tox.novg.net", 33445, 0xD5, 0x27, 0xE5, 0x84, 0x7F, 0x83, 0x30, 0xD6, 0x28, 0xDA, 0xB1, 0x81, 0x4F, 0x0A, 0x42, 0x2F, 0x6D, 0xC9, 0xD0, 0xA3, 0x00, 0xE6, 0xC3, 0x57, 0x63, 0x4E, 0xE2, 0xDA, 0x88, 0xC3, 0x54, 0x63, }, { nullptr, 0, 0 }, }; void bootstrap_tox_live_network(Tox *tox, bool enable_tcp) { ck_assert(tox != nullptr); for (size_t j = 0; bootstrap_nodes[j].ip != nullptr; ++j) { const char *ip = bootstrap_nodes[j].ip; uint16_t port = bootstrap_nodes[j].port; const uint8_t *key = bootstrap_nodes[j].key; Tox_Err_Bootstrap err; tox_bootstrap(tox, ip, port, key, &err); if (err != TOX_ERR_BOOTSTRAP_OK) { fprintf(stderr, "Failed to bootstrap node %zu (%s): error %d\n", j, ip, err); } if (enable_tcp) { tox_add_tcp_relay(tox, ip, port, key, &err); if (err != TOX_ERR_BOOTSTRAP_OK) { fprintf(stderr, "Failed to add TCP relay %zu (%s): error %d\n", j, ip, err); } } } } bool all_connected(const AutoTox *autotoxes, uint32_t tox_count) { if (tox_count) { ck_assert(autotoxes != nullptr); } for (uint32_t i = 0; i < tox_count; ++i) { if (tox_self_get_connection_status(autotoxes[i].tox) == TOX_CONNECTION_NONE) { return false; } } return true; } bool all_friends_connected(const AutoTox *autotoxes, uint32_t tox_count) { if (tox_count) { ck_assert(autotoxes != nullptr); } for (uint32_t i = 0; i < tox_count; ++i) { const size_t friend_count = tox_self_get_friend_list_size(autotoxes[i].tox); for (size_t j = 0; j < friend_count; ++j) { if (tox_friend_get_connection_status(autotoxes[i].tox, j, nullptr) == TOX_CONNECTION_NONE) { return false; } } } return true; } void iterate_all_wait(AutoTox *autotoxes, uint32_t tox_count, uint32_t wait) { if (tox_count) { ck_assert(autotoxes != nullptr); } for (uint32_t i = 0; i < tox_count; ++i) { if (autotoxes[i].alive) { if (autotoxes[i].events) { Tox_Err_Events_Iterate err; Tox_Events *events = tox_events_iterate(autotoxes[i].tox, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(autotoxes[i].dispatch, events, &autotoxes[i]); tox_events_free(events); } else { tox_iterate(autotoxes[i].tox, &autotoxes[i]); } autotoxes[i].clock += wait; } } /* Also actually sleep a little, to allow for local network processing */ c_sleep(5); } static uint64_t get_state_clock_callback(void *user_data) { const uint64_t *clock = (const uint64_t *)user_data; return *clock; } void set_mono_time_callback(AutoTox *autotox) { ck_assert(autotox != nullptr); Mono_Time *mono_time = autotox->tox->mono_time; autotox->clock = current_time_monotonic(mono_time); ck_assert_msg(autotox->clock >= 1000, "clock is too low (not initialised?): %lu", (unsigned long)autotox->clock); mono_time_set_current_time_callback(mono_time, nullptr, nullptr); // set to default first mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &autotox->clock); } void save_autotox(AutoTox *autotox) { ck_assert(autotox != nullptr); fprintf(stderr, "Saving #%u\n", autotox->index); free(autotox->save_state); autotox->save_state = nullptr; autotox->save_size = tox_get_savedata_size(autotox->tox); ck_assert_msg(autotox->save_size > 0, "save is invalid size %u", (unsigned)autotox->save_size); autotox->save_state = (uint8_t *)malloc(autotox->save_size); ck_assert_msg(autotox->save_state != nullptr, "malloc failed"); tox_get_savedata(autotox->tox, autotox->save_state); } void kill_autotox(AutoTox *autotox) { ck_assert(autotox != nullptr); ck_assert(autotox->alive); fprintf(stderr, "Killing #%u\n", autotox->index); autotox->alive = false; tox_dispatch_free(autotox->dispatch); tox_kill(autotox->tox); } void reload(AutoTox *autotox) { ck_assert(autotox != nullptr); if (autotox->alive) { kill_autotox(autotox); } fprintf(stderr, "Reloading #%u\n", autotox->index); ck_assert(autotox->save_state != nullptr); struct Tox_Options *const options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_ipv6_enabled(options, USE_IPV6); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, autotox->save_state, autotox->save_size); autotox->tox = tox_new_log(options, nullptr, &autotox->index); ck_assert(autotox->tox != nullptr); autotox->dispatch = tox_dispatch_new(nullptr); ck_assert(autotox->dispatch != nullptr); if (autotox->events) { tox_events_init(autotox->tox); } tox_options_free(options); set_mono_time_callback(autotox); autotox->alive = true; } static void initialise_autotox(struct Tox_Options *options, AutoTox *autotox, uint32_t index, uint32_t state_size, Run_Auto_Options *autotest_opts) { autotox->index = index; autotox->events = autotest_opts->events; Tox_Err_New err = TOX_ERR_NEW_OK; if (index == 0) { struct Tox_Options *default_opts = tox_options_new(nullptr); ck_assert(default_opts != nullptr); tox_options_set_ipv6_enabled(default_opts, USE_IPV6); if (options == nullptr) { options = default_opts; } if (tox_options_get_udp_enabled(options)) { tox_options_set_tcp_port(options, 0); autotest_opts->tcp_port = 0; autotox->tox = tox_new_log(options, &err, &autotox->index); ck_assert_msg(err == TOX_ERR_NEW_OK, "unexpected tox_new error: %d", err); } else { // Try a few ports for the TCP relay. for (uint16_t tcp_port = autotest_opts->tcp_port; tcp_port < autotest_opts->tcp_port + 200; ++tcp_port) { tox_options_set_tcp_port(options, tcp_port); autotox->tox = tox_new_log(options, &err, &autotox->index); if (autotox->tox != nullptr) { autotest_opts->tcp_port = tcp_port; break; } ck_assert_msg(err == TOX_ERR_NEW_PORT_ALLOC, "unexpected tox_new error (expected PORT_ALLOC): %d", err); } } tox_options_free(default_opts); } else { // No TCP relay enabled for all the other toxes. if (options != nullptr) { tox_options_set_tcp_port(options, 0); } autotox->tox = tox_new_log(options, &err, &autotox->index); } ck_assert_msg(autotox->tox != nullptr, "failed to create tox instance #%u (error = %d)", index, err); set_mono_time_callback(autotox); autotox->dispatch = tox_dispatch_new(nullptr); ck_assert(autotox->dispatch != nullptr); if (autotox->events) { tox_events_init(autotox->tox); } autotox->alive = true; autotox->save_state = nullptr; if (state_size > 0) { autotox->state = calloc(1, state_size); ck_assert(autotox->state != nullptr); ck_assert_msg(autotox->state != nullptr, "failed to allocate state"); } else { autotox->state = nullptr; } if (autotest_opts->init_autotox != nullptr) { autotest_opts->init_autotox(autotox, index); } } static void autotox_add_friend(AutoTox *autotoxes, uint32_t adding, uint32_t added) { uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(autotoxes[added].tox, public_key); Tox_Err_Friend_Add err; tox_friend_add_norequest(autotoxes[adding].tox, public_key, &err); ck_assert(err == TOX_ERR_FRIEND_ADD_OK); } static void initialise_friend_graph(Graph_Type graph, uint32_t num_toxes, AutoTox *autotoxes) { if (graph == GRAPH_LINEAR) { printf("toxes #%d-#%u each add adjacent toxes as friends\n", 0, num_toxes - 1); for (uint32_t i = 0; i < num_toxes; ++i) { for (uint32_t j = i - 1; j != i + 3; j += 2) { if (j < num_toxes) { autotox_add_friend(autotoxes, i, j); } } } } else if (graph == GRAPH_COMPLETE) { printf("toxes #%d-#%u add each other as friends\n", 0, num_toxes - 1); for (uint32_t i = 0; i < num_toxes; ++i) { for (uint32_t j = 0; j < num_toxes; ++j) { if (i != j) { autotox_add_friend(autotoxes, i, j); } } } } else { ck_abort_msg("Unknown graph type"); } } static void bootstrap_autotoxes(const Tox_Options *options, uint32_t tox_count, const Run_Auto_Options *autotest_opts, AutoTox *autotoxes) { const bool udp_enabled = options != nullptr ? tox_options_get_udp_enabled(options) : true; printf("bootstrapping all toxes off tox 0\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(autotoxes[0].tox, dht_key); const uint16_t dht_port = tox_self_get_udp_port(autotoxes[0].tox, nullptr); for (uint32_t i = 1; i < tox_count; ++i) { Tox_Err_Bootstrap err; tox_bootstrap(autotoxes[i].tox, "localhost", dht_port, dht_key, &err); ck_assert_msg(err == TOX_ERR_BOOTSTRAP_OK, "bootstrap error for port %d: %d", dht_port, err); } if (!udp_enabled) { ck_assert(autotest_opts->tcp_port != 0); printf("bootstrapping all toxes to local TCP relay running on port %d\n", autotest_opts->tcp_port); for (uint32_t i = 0; i < tox_count; ++i) { Tox_Err_Bootstrap err; tox_add_tcp_relay(autotoxes[i].tox, "localhost", autotest_opts->tcp_port, dht_key, &err); ck_assert(err == TOX_ERR_BOOTSTRAP_OK); } } } typedef void autotox_test_cb(AutoTox *autotoxes); void run_auto_test(struct Tox_Options *options, uint32_t tox_count, autotox_test_cb *test, uint32_t state_size, Run_Auto_Options *autotest_opts) { printf("initialising %u toxes\n", tox_count); AutoTox *autotoxes = (AutoTox *)calloc(tox_count, sizeof(AutoTox)); ck_assert(autotoxes != nullptr); for (uint32_t i = 0; i < tox_count; ++i) { initialise_autotox(options, &autotoxes[i], i, state_size, autotest_opts); } initialise_friend_graph(autotest_opts->graph, tox_count, autotoxes); bootstrap_autotoxes(options, tox_count, autotest_opts, autotoxes); do { iterate_all_wait(autotoxes, tox_count, ITERATION_INTERVAL); } while (!all_connected(autotoxes, tox_count)); printf("toxes are online\n"); do { iterate_all_wait(autotoxes, tox_count, ITERATION_INTERVAL); } while (!all_friends_connected(autotoxes, tox_count)); printf("tox clients connected\n"); test(autotoxes); for (uint32_t i = 0; i < tox_count; ++i) { tox_dispatch_free(autotoxes[i].dispatch); tox_kill(autotoxes[i].tox); free(autotoxes[i].state); free(autotoxes[i].save_state); } free(autotoxes); } static const char *tox_log_level_name(Tox_Log_Level level) { switch (level) { case TOX_LOG_LEVEL_TRACE: return "TRACE"; case TOX_LOG_LEVEL_DEBUG: return "DEBUG"; case TOX_LOG_LEVEL_INFO: return "INFO"; case TOX_LOG_LEVEL_WARNING: return "WARNING"; case TOX_LOG_LEVEL_ERROR: return "ERROR"; } return ""; } void print_debug_log(Tox *m, Tox_Log_Level level, const char *file, uint32_t line, const char *func, const char *message, void *user_data) { if (level == TOX_LOG_LEVEL_TRACE) { return; } const uint32_t index = user_data ? *(uint32_t *)user_data : 0; fprintf(stderr, "[#%u] %s %s:%u\t%s:\t%s\n", index, tox_log_level_name(level), file, line, func, message); if (level == TOX_LOG_LEVEL_ERROR && ABORT_ON_LOG_ERROR) { fputs("Aborting test program\n", stderr); abort(); } } void print_debug_logger(void *context, Logger_Level level, const char *file, int line, const char *func, const char *message, void *userdata) { print_debug_log(nullptr, (Tox_Log_Level) level, file, (uint32_t) line, func, message, userdata); } Tox *tox_new_log_lan(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data, bool lan_discovery) { struct Tox_Options *log_options = options; if (log_options == nullptr) { log_options = tox_options_new(nullptr); } assert(log_options != nullptr); tox_options_set_ipv6_enabled(log_options, USE_IPV6); tox_options_set_local_discovery_enabled(log_options, lan_discovery); // Use a higher start port for non-LAN-discovery tests so it's more likely for the LAN discovery // test to get the default port 33445. const uint16_t start_port = lan_discovery ? 33445 : 33545; tox_options_set_start_port(log_options, start_port); tox_options_set_end_port(log_options, start_port + 2000); tox_options_set_log_callback(log_options, &print_debug_log); tox_options_set_log_user_data(log_options, log_user_data); Tox *tox = tox_new(log_options, err); if (options == nullptr) { tox_options_free(log_options); } return tox; } Tox *tox_new_log(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data) { return tox_new_log_lan(options, err, log_user_data, false); } c-toxcore-0.2.20/auto_tests/auto_test_support.h0000644060175106017510000000401514714247532017645 0ustar robin#ifndef RUN_AUTO_TEST_H #define RUN_AUTO_TEST_H #include // calloc, free #include "check_compat.h" #include "../testing/misc_tools.h" #include "../toxcore/Messenger.h" #include "../toxcore/mono_time.h" #include "../toxcore/tox_dispatch.h" typedef struct AutoTox { Tox *tox; Tox_Dispatch *dispatch; uint32_t index; uint64_t clock; size_t save_size; uint8_t *save_state; bool alive; bool events; void *state; } AutoTox; bool all_connected(const AutoTox *autotoxes, uint32_t tox_count); bool all_friends_connected(const AutoTox *autotoxes, uint32_t tox_count); void iterate_all_wait(AutoTox *autotoxes, uint32_t tox_count, uint32_t wait); void save_autotox(AutoTox *autotox); void kill_autotox(AutoTox *autotox); void reload(AutoTox *autotox); void set_mono_time_callback(AutoTox *autotox); typedef enum Graph_Type { GRAPH_COMPLETE = 0, GRAPH_LINEAR, } Graph_Type; typedef struct Run_Auto_Options { Graph_Type graph; void (*init_autotox)(AutoTox *autotox, uint32_t n); uint16_t tcp_port; bool events; } Run_Auto_Options; Run_Auto_Options default_run_auto_options(void); void run_auto_test(struct Tox_Options *options, uint32_t tox_count, void test(AutoTox *autotoxes), uint32_t state_size, Run_Auto_Options *autotest_opts); void bootstrap_tox_live_network(Tox *tox, bool enable_tcp); // Use this function when setting the log callback on a Tox* object void print_debug_log(Tox *m, Tox_Log_Level level, const char *file, uint32_t line, const char *func, const char *message, void *user_data); // Use this function when setting the log callback on a Logger object void print_debug_logger(void *context, Logger_Level level, const char *file, int line, const char *func, const char *message, void *userdata); Tox *tox_new_log(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data); Tox *tox_new_log_lan(struct Tox_Options *options, Tox_Err_New *err, void *log_user_data, bool lan_discovery); #endif c-toxcore-0.2.20/auto_tests/bootstrap_test.c0000644060175106017510000000152514714247532017114 0ustar robin#include #include "../testing/misc_tools.h" #include "check_compat.h" #include "auto_test_support.h" int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Tox *tox_udp = tox_new_log(nullptr, nullptr, nullptr); bootstrap_tox_live_network(tox_udp, false); printf("Waiting for connection"); do { printf("."); fflush(stdout); tox_iterate(tox_udp, nullptr); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox_udp) == TOX_CONNECTION_NONE); const Tox_Connection status = tox_self_get_connection_status(tox_udp); ck_assert_msg(status == TOX_CONNECTION_UDP, "expected connection status to be UDP, but got %d", status); printf("Connection (UDP): %d\n", tox_self_get_connection_status(tox_udp)); tox_kill(tox_udp); return 0; } c-toxcore-0.2.20/auto_tests/BUILD.bazel0000644060175106017510000000437714714247532015562 0ustar robinload("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") cc_library( name = "check_compat", testonly = True, hdrs = ["check_compat.h"], ) cc_library( name = "auto_test_support", testonly = True, srcs = ["auto_test_support.c"], hdrs = ["auto_test_support.h"], deps = [ ":check_compat", "//c-toxcore/testing:misc_tools", "//c-toxcore/toxcore:Messenger", "//c-toxcore/toxcore:mono_time", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", ], ) flaky_tests = { "crypto_core_test": True, "lan_discovery_test": True, "save_load_test": True, "tox_many_tcp_test": True, } extra_args = { "proxy_test": ["$(location //c-toxcore/other/proxy)"], } extra_data = { "proxy_test": ["//c-toxcore/other/proxy"], } [cc_test( name = src[:-2], size = "small", srcs = [src], args = ["$(location %s)" % src] + extra_args.get( src[:-2], [], ), data = glob(["data/*"]) + extra_data.get( src[:-2], [], ), flaky = flaky_tests.get( src[:-2], False, ), deps = [ ":auto_test_support", ":check_compat", "//c-toxcore/testing:misc_tools", "//c-toxcore/toxav", "//c-toxcore/toxcore:Messenger", "//c-toxcore/toxcore:TCP_client", "//c-toxcore/toxcore:TCP_common", "//c-toxcore/toxcore:TCP_connection", "//c-toxcore/toxcore:TCP_server", "//c-toxcore/toxcore:announce", "//c-toxcore/toxcore:ccompat", "//c-toxcore/toxcore:crypto_core", "//c-toxcore/toxcore:forwarding", "//c-toxcore/toxcore:friend_connection", "//c-toxcore/toxcore:logger", "//c-toxcore/toxcore:mono_time", "//c-toxcore/toxcore:net_crypto", "//c-toxcore/toxcore:network", "//c-toxcore/toxcore:onion", "//c-toxcore/toxcore:onion_announce", "//c-toxcore/toxcore:onion_client", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", "//c-toxcore/toxcore:util", "//c-toxcore/toxencryptsave", "@libsodium", "@libvpx", ], ) for src in glob(["*_test.c"])] c-toxcore-0.2.20/auto_tests/check_compat.h0000644060175106017510000000274114714247532016466 0ustar robin#ifndef C_TOXCORE_AUTO_TESTS_CHECK_COMPAT_H #define C_TOXCORE_AUTO_TESTS_CHECK_COMPAT_H #include "../toxcore/ccompat.h" #include #include #define ck_assert(ok) do { \ if (!(ok)) { \ fprintf(stderr, "%s:%d: failed `%s'\n", __FILE__, __LINE__, #ok); \ exit(7); \ } \ } while (0) #define ck_assert_msg(ok, ...) do { \ if (!(ok)) { \ fprintf(stderr, "%s:%d: failed `%s': ", __FILE__, __LINE__, #ok); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ exit(7); \ } \ } while (0) #define ck_abort_msg(...) do { \ fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ exit(7); \ } while (0) #endif // C_TOXCORE_AUTO_TESTS_CHECK_COMPAT_H c-toxcore-0.2.20/auto_tests/CMakeLists.txt0000644060175106017510000000763314714247532016442 0ustar robinset(TEST_TIMEOUT_SECONDS "" CACHE STRING "Limit runtime of each test to the number of seconds specified") add_library(auto_test_support auto_test_support.c auto_test_support.h) target_link_libraries(auto_test_support PRIVATE misc_tools) if(TARGET toxcore_static) target_link_libraries(auto_test_support PRIVATE toxcore_static) else() target_link_libraries(auto_test_support PRIVATE toxcore_shared) endif() if(TARGET PThreads4W::PThreads4W) target_link_libraries(auto_test_support PRIVATE PThreads4W::PThreads4W) elseif(TARGET Threads::Threads) target_link_libraries(auto_test_support PRIVATE Threads::Threads) endif() function(auto_test target) add_executable(auto_${target}_test ${target}_test.c) target_link_libraries(auto_${target}_test PRIVATE misc_tools auto_test_support) if(TARGET toxcore_static) target_link_libraries(auto_${target}_test PRIVATE toxcore_static) else() target_link_libraries(auto_${target}_test PRIVATE toxcore_shared) endif() if(TARGET PThreads4W::PThreads4W) target_link_libraries(auto_${target}_test PRIVATE PThreads4W::PThreads4W) elseif(TARGET Threads::Threads) target_link_libraries(auto_${target}_test PRIVATE Threads::Threads) endif() add_test(NAME ${target} COMMAND ${CROSSCOMPILING_EMULATOR} auto_${target}_test) set_tests_properties(${target} PROPERTIES TIMEOUT "${TEST_TIMEOUT_SECONDS}") # add the source dir as environment variable, so the testdata can be found set_tests_properties(${target} PROPERTIES ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw;srcdir=${CMAKE_CURRENT_SOURCE_DIR}") endfunction() auto_test(TCP) auto_test(announce) auto_test(conference) auto_test(conference_double_invite) auto_test(conference_invite_merge) auto_test(conference_peer_nick) auto_test(conference_simple) auto_test(conference_two) auto_test(crypto) #auto_test(dht) # Doesn't work with UNITY_BUILD. auto_test(dht_getnodes_api) auto_test(encryptsave) auto_test(file_saving) auto_test(file_streaming) auto_test(file_transfer) auto_test(forwarding) auto_test(friend_connection) auto_test(friend_request) auto_test(friend_request_spam) auto_test(group_general) auto_test(group_invite) auto_test(group_message) auto_test(group_moderation) auto_test(group_save) auto_test(group_state) auto_test(group_sync) auto_test(group_tcp) auto_test(group_topic) auto_test(invalid_tcp_proxy) auto_test(invalid_udp_proxy) auto_test(lan_discovery) auto_test(lossless_packet) auto_test(lossy_packet) auto_test(network) auto_test(onion) auto_test(overflow_recvq) auto_test(overflow_sendq) auto_test(reconnect) auto_test(save_friend) auto_test(save_load) auto_test(send_message) auto_test(set_name) auto_test(set_status_message) auto_test(tox_dispatch) auto_test(tox_events) auto_test(tox_many) auto_test(tox_many_tcp) auto_test(tox_strncasecmp) auto_test(typing) auto_test(version) auto_test(save_compatibility) target_include_directories(auto_encryptsave_test SYSTEM PRIVATE ${LIBSODIUM_INCLUDE_DIRS}) if(NON_HERMETIC_TESTS) auto_test(bootstrap) auto_test(tcp_relay) endif() if(BUILD_TOXAV) auto_test(conference_av) auto_test(toxav_basic) auto_test(toxav_many) if(MSVC) target_link_libraries(auto_toxav_basic_test PRIVATE PkgConfig::VPX) target_link_libraries(auto_toxav_many_test PRIVATE PkgConfig::VPX) else() target_link_libraries(auto_toxav_basic_test PRIVATE ${VPX_LIBRARIES}) target_link_directories(auto_toxav_basic_test PRIVATE ${VPX_LIBRARY_DIRS}) target_include_directories(auto_toxav_basic_test SYSTEM PRIVATE ${VPX_INCLUDE_DIRS}) target_compile_options(auto_toxav_basic_test PRIVATE ${VPX_CFLAGS_OTHER}) target_link_libraries(auto_toxav_many_test PRIVATE ${VPX_LIBRARIES}) target_link_directories(auto_toxav_many_test PRIVATE ${VPX_LIBRARY_DIRS}) target_include_directories(auto_toxav_many_test SYSTEM PRIVATE ${VPX_INCLUDE_DIRS}) target_compile_options(auto_toxav_many_test PRIVATE ${VPX_CFLAGS_OTHER}) endif() endif() if(PROXY_TEST) auto_test(proxy) endif() c-toxcore-0.2.20/auto_tests/conference_av_test.c0000644060175106017510000003761514714247532017705 0ustar robin/* Auto Tests: Conferences AV. */ #include #include #include #include #include "../toxav/toxav.h" #include "check_compat.h" #define NUM_AV_GROUP_TOX 16 #define NUM_AV_DISCONNECT (NUM_AV_GROUP_TOX / 2) #define NUM_AV_DISABLE (NUM_AV_GROUP_TOX / 2) #include "auto_test_support.h" typedef struct State { bool invited_next; uint32_t received_audio_peers[NUM_AV_GROUP_TOX]; uint32_t received_audio_num; } State; static void handle_self_connection_status( const Tox_Event_Self_Connection_Status *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; const Tox_Connection connection_status = tox_event_self_connection_status_get_connection_status(event); if (connection_status != TOX_CONNECTION_NONE) { printf("tox #%u: is now connected\n", autotox->index); } else { printf("tox #%u: is now disconnected\n", autotox->index); } } static void handle_friend_connection_status( const Tox_Event_Friend_Connection_Status *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; const uint32_t friendnumber = tox_event_friend_connection_status_get_friend_number(event); const Tox_Connection connection_status = tox_event_friend_connection_status_get_connection_status(event); if (connection_status != TOX_CONNECTION_NONE) { printf("tox #%u: is now connected to friend %u\n", autotox->index, friendnumber); } else { printf("tox #%u: is now disconnected from friend %u\n", autotox->index, friendnumber); } } static void audio_callback(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *user_data) { if (samples == 0) { return; } const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; for (uint32_t i = 0; i < state->received_audio_num; ++i) { if (state->received_audio_peers[i] == peernumber) { return; } } ck_assert(state->received_audio_num < NUM_AV_GROUP_TOX); state->received_audio_peers[state->received_audio_num] = peernumber; ++state->received_audio_num; } static void handle_conference_invite( const Tox_Event_Conference_Invite *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); const Tox_Conference_Type type = tox_event_conference_invite_get_type(event); const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); const size_t length = tox_event_conference_invite_get_cookie_length(event); ck_assert_msg(type == TOX_CONFERENCE_TYPE_AV, "tox #%u: wrong conference type: %d", autotox->index, type); ck_assert_msg(toxav_join_av_groupchat(autotox->tox, friend_number, cookie, length, audio_callback, user_data) == 0, "tox #%u: failed to join group", autotox->index); } static void handle_conference_connected( const Tox_Event_Conference_Connected *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; if (state->invited_next || tox_self_get_friend_list_size(autotox->tox) <= 1) { return; } Tox_Err_Conference_Invite err; tox_conference_invite(autotox->tox, 1, 0, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", autotox->index, err); printf("tox #%u: invited next friend\n", autotox->index); state->invited_next = true; } static bool toxes_are_disconnected_from_group(uint32_t tox_count, AutoTox *autotoxes, const bool *disconnected) { uint32_t num_disconnected = 0; for (uint32_t i = 0; i < tox_count; ++i) { num_disconnected += disconnected[i]; } for (uint32_t i = 0; i < tox_count; ++i) { if (disconnected[i]) { continue; } if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) > tox_count - num_disconnected) { return false; } } return true; } static void disconnect_toxes(uint32_t tox_count, AutoTox *autotoxes, const bool *disconnect, const bool *exclude) { /* Fake a network outage for a set of peers D by iterating only the other * peers D' until the connections time out according to D', then iterating * only D until the connections time out according to D. */ VLA(bool, disconnect_now, tox_count); bool invert = false; do { for (uint32_t i = 0; i < tox_count; ++i) { disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]); } do { for (uint32_t i = 0; i < tox_count; ++i) { if (!disconnect_now[i]) { Tox_Err_Events_Iterate err; Tox_Events *events = tox_events_iterate(autotoxes[i].tox, true, &err); tox_dispatch_invoke(autotoxes[i].dispatch, events, &autotoxes[i]); tox_events_free(events); autotoxes[i].clock += 1000; } } c_sleep(20); } while (!toxes_are_disconnected_from_group(tox_count, autotoxes, disconnect_now)); invert = !invert; } while (invert); } static bool all_connected_to_group(uint32_t tox_count, AutoTox *autotoxes) { for (uint32_t i = 0; i < tox_count; ++i) { if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) < tox_count) { return false; } } return true; } /** * returns a random index at which a list of booleans is false * (some such index is required to exist) */ static uint32_t random_false_index(const Random *rng, const bool *list, const uint32_t length) { uint32_t index; do { index = random_u32(rng) % length; } while (list[index]); return index; } static bool all_got_audio(AutoTox *autotoxes, const bool *disabled) { uint32_t num_disabled = 0; for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { num_disabled += disabled[i]; } for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { const State *state = (const State *)autotoxes[i].state; if (disabled[i] ^ (state->received_audio_num != NUM_AV_GROUP_TOX - num_disabled - 1)) { return false; } } return true; } static void reset_received_audio(AutoTox *autotoxes) { for (uint32_t j = 0; j < NUM_AV_GROUP_TOX; ++j) { ((State *)autotoxes[j].state)->received_audio_num = 0; } } #define GROUP_AV_TEST_SAMPLES 960 /* must have * GROUP_AV_AUDIO_ITERATIONS - NUM_AV_GROUP_TOX >= 2^n >= GROUP_JBUF_SIZE * for some n, to give messages time to be relayed and to let the jitter * buffers fill up. */ #define GROUP_AV_AUDIO_ITERATIONS (8 + NUM_AV_GROUP_TOX) static bool test_audio(AutoTox *autotoxes, const bool *disabled, bool quiet) { if (!quiet) { printf("testing sending and receiving audio\n"); } const int16_t pcm[GROUP_AV_TEST_SAMPLES] = {0}; reset_received_audio(autotoxes); for (uint32_t n = 0; n < GROUP_AV_AUDIO_ITERATIONS; ++n) { for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { if (disabled[i]) { continue; } if (toxav_group_send_audio(autotoxes[i].tox, 0, pcm, GROUP_AV_TEST_SAMPLES, 1, 48000) != 0) { if (!quiet) { ck_abort_msg("#%u failed to send audio", autotoxes[i].index); } return false; } } iterate_all_wait(autotoxes, NUM_AV_GROUP_TOX, ITERATION_INTERVAL); if (all_got_audio(autotoxes, disabled)) { return true; } } if (!quiet) { ck_abort_msg("group failed to receive audio"); } return false; } static void test_eventual_audio(AutoTox *autotoxes, const bool *disabled, uint64_t timeout) { uint64_t start = autotoxes[0].clock; while (autotoxes[0].clock < start + timeout) { if (!test_audio(autotoxes, disabled, true)) { continue; } // It needs to succeed twice in a row for the test to pass. if (test_audio(autotoxes, disabled, true)) { printf("audio test successful after %d seconds\n", (int)((autotoxes[0].clock - start) / 1000)); return; } } printf("audio seems not to be getting through: testing again with errors.\n"); test_audio(autotoxes, disabled, false); } static void do_audio(AutoTox *autotoxes, uint32_t iterations) { const int16_t pcm[GROUP_AV_TEST_SAMPLES] = {0}; printf("running audio for %u iterations\n", iterations); for (uint32_t f = 0; f < iterations; ++f) { for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { ck_assert_msg(toxav_group_send_audio(autotoxes[i].tox, 0, pcm, GROUP_AV_TEST_SAMPLES, 1, 48000) == 0, "#%u failed to send audio", autotoxes[i].index); iterate_all_wait(autotoxes, NUM_AV_GROUP_TOX, ITERATION_INTERVAL); } } } // should agree with value in groupav.c #define GROUP_JBUF_DEAD_SECONDS 4 #define JITTER_SETTLE_TIME (GROUP_JBUF_DEAD_SECONDS*1000 + NUM_AV_GROUP_TOX*ITERATION_INTERVAL*(GROUP_AV_AUDIO_ITERATIONS+1)) static void run_conference_tests(AutoTox *autotoxes) { const Random *rng = os_random(); ck_assert(rng != nullptr); bool disabled[NUM_AV_GROUP_TOX] = {0}; test_audio(autotoxes, disabled, false); /* have everyone send audio for a bit so we can test that the audio * sequnums dropping to 0 on restart isn't a problem */ do_audio(autotoxes, 20); printf("letting random toxes timeout\n"); bool disconnected[NUM_AV_GROUP_TOX] = {0}; bool restarting[NUM_AV_GROUP_TOX] = {0}; ck_assert(NUM_AV_DISCONNECT < NUM_AV_GROUP_TOX); for (uint32_t i = 0; i < NUM_AV_DISCONNECT; ++i) { uint32_t disconnect = random_false_index(rng, disconnected, NUM_AV_GROUP_TOX); disconnected[disconnect] = true; if (i < NUM_AV_DISCONNECT / 2) { restarting[disconnect] = true; printf("Restarting #%u\n", autotoxes[disconnect].index); } else { printf("Disconnecting #%u\n", autotoxes[disconnect].index); } } for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { if (restarting[i]) { save_autotox(&autotoxes[i]); kill_autotox(&autotoxes[i]); } } disconnect_toxes(NUM_AV_GROUP_TOX, autotoxes, disconnected, restarting); for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { if (restarting[i]) { reload(&autotoxes[i]); } } printf("reconnecting toxes\n"); do { iterate_all_wait(autotoxes, NUM_AV_GROUP_TOX, ITERATION_INTERVAL); } while (!all_connected_to_group(NUM_AV_GROUP_TOX, autotoxes)); for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { if (restarting[i]) { ck_assert_msg(!toxav_groupchat_av_enabled(autotoxes[i].tox, 0), "#%u restarted but av enabled", autotoxes[i].index); ck_assert_msg(toxav_groupchat_enable_av(autotoxes[i].tox, 0, audio_callback, &autotoxes[i]) == 0, "#%u failed to re-enable av", autotoxes[i].index); ck_assert_msg(toxav_groupchat_av_enabled(autotoxes[i].tox, 0), "#%u av not enabled even after enabling", autotoxes[i].index); } } printf("testing audio\n"); /* Allow time for the jitter buffers to reset and for the group to become * connected enough for lossy messages to get through * (all_connected_to_group() only checks lossless connectivity, which is a * looser condition). */ test_eventual_audio(autotoxes, disabled, JITTER_SETTLE_TIME + NUM_AV_GROUP_TOX * 1000); printf("testing disabling av\n"); ck_assert(NUM_AV_DISABLE < NUM_AV_GROUP_TOX); for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) { uint32_t disable = random_false_index(rng, disabled, NUM_AV_GROUP_TOX); disabled[disable] = true; printf("Disabling #%u\n", autotoxes[disable].index); ck_assert_msg(toxav_groupchat_enable_av(autotoxes[disable].tox, 0, audio_callback, &autotoxes[disable]) != 0, "#%u could enable already enabled av!", autotoxes[i].index); ck_assert_msg(toxav_groupchat_disable_av(autotoxes[disable].tox, 0) == 0, "#%u failed to disable av", autotoxes[i].index); } // Run test without error to clear out messages from now-disabled peers. test_audio(autotoxes, disabled, true); printf("testing audio with some peers having disabled their av\n"); test_audio(autotoxes, disabled, false); for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) { if (!disabled[i]) { continue; } disabled[i] = false; ck_assert_msg(toxav_groupchat_disable_av(autotoxes[i].tox, 0) != 0, "#%u could disable already disabled av!", autotoxes[i].index); ck_assert_msg(!toxav_groupchat_av_enabled(autotoxes[i].tox, 0), "#%u av enabled after disabling", autotoxes[i].index); ck_assert_msg(toxav_groupchat_enable_av(autotoxes[i].tox, 0, audio_callback, &autotoxes[i]) == 0, "#%u failed to re-enable av", autotoxes[i].index); } printf("testing audio after re-enabling all av\n"); test_eventual_audio(autotoxes, disabled, JITTER_SETTLE_TIME); } static void test_groupav(AutoTox *autotoxes) { const time_t test_start_time = time(nullptr); for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { tox_events_callback_self_connection_status(autotoxes[i].dispatch, handle_self_connection_status); tox_events_callback_friend_connection_status(autotoxes[i].dispatch, handle_friend_connection_status); tox_events_callback_conference_invite(autotoxes[i].dispatch, handle_conference_invite); tox_events_callback_conference_connected(autotoxes[i].dispatch, handle_conference_connected); } ck_assert_msg(toxav_add_av_groupchat(autotoxes[0].tox, audio_callback, &autotoxes[0]) != -1, "failed to create group"); printf("tox #%u: inviting its first friend\n", autotoxes[0].index); ck_assert_msg(tox_conference_invite(autotoxes[0].tox, 0, 0, nullptr) != 0, "failed to invite friend"); ((State *)autotoxes[0].state)->invited_next = true; printf("waiting for invitations to be made\n"); uint32_t invited_count = 0; do { iterate_all_wait(autotoxes, NUM_AV_GROUP_TOX, ITERATION_INTERVAL); invited_count = 0; for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { invited_count += ((State *)autotoxes[i].state)->invited_next; } } while (invited_count != NUM_AV_GROUP_TOX - 1); uint64_t pregroup_clock = autotoxes[0].clock; printf("waiting for all toxes to be in the group\n"); uint32_t fully_connected_count = 0; do { fully_connected_count = 0; iterate_all_wait(autotoxes, NUM_AV_GROUP_TOX, ITERATION_INTERVAL); for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) { Tox_Err_Conference_Peer_Query err; uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, &err); if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { peer_count = 0; } fully_connected_count += peer_count == NUM_AV_GROUP_TOX; } } while (fully_connected_count != NUM_AV_GROUP_TOX); printf("group connected, took %d seconds\n", (int)((autotoxes[0].clock - pregroup_clock) / 1000)); run_conference_tests(autotoxes); printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time)); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, NUM_AV_GROUP_TOX, test_groupav, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/conference_double_invite_test.c0000644060175106017510000000646114714247532022122 0ustar robin#include #include typedef struct State { bool self_online; bool friend_online; bool joined; uint32_t conference; } State; #include "auto_test_support.h" static void handle_conference_invite( const Tox_Event_Conference_Invite *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); const Tox_Conference_Type type = tox_event_conference_invite_get_type(event); const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); const size_t length = tox_event_conference_invite_get_cookie_length(event); fprintf(stderr, "handle_conference_invite(#%u, %u, %d, uint8_t[%u], _)\n", autotox->index, friend_number, type, (unsigned)length); fprintf(stderr, "tox%u joining conference\n", autotox->index); ck_assert_msg(!state->joined, "invitation callback generated for already joined conference"); if (friend_number != UINT32_MAX) { Tox_Err_Conference_Join err; state->conference = tox_conference_join(autotox->tox, friend_number, cookie, length, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "attempting to join the conference returned with an error: %d", err); fprintf(stderr, "tox%u joined conference %u\n", autotox->index, state->conference); state->joined = true; } } static void conference_double_invite_test(AutoTox *autotoxes) { // Conference callbacks. tox_events_callback_conference_invite(autotoxes[0].dispatch, handle_conference_invite); tox_events_callback_conference_invite(autotoxes[1].dispatch, handle_conference_invite); State *state[2]; state[0] = (State *)autotoxes[0].state; state[1] = (State *)autotoxes[1].state; { // Create new conference, tox0 is the founder. Tox_Err_Conference_New err; state[0]->conference = tox_conference_new(autotoxes[0].tox, &err); state[0]->joined = true; ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "attempting to create a new conference returned with an error: %d", err); fprintf(stderr, "Created conference: index=%u\n", state[0]->conference); } { // Invite friend. Tox_Err_Conference_Invite err; tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "attempting to invite a friend returned with an error: %d", err); fprintf(stderr, "tox0 invited tox1\n"); } fprintf(stderr, "Waiting for invitation to arrive\n"); do { iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } while (!state[0]->joined || !state[1]->joined); fprintf(stderr, "Invitations accepted\n"); fprintf(stderr, "Sending second invitation; should be ignored\n"); tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, nullptr); iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, conference_double_invite_test, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/conference_invite_merge_test.c0000644060175106017510000001350214714247532021741 0ustar robin#include #include #include typedef struct State { bool connected; uint32_t conference; } State; #define NUM_INVITE_MERGE_TOX 5 #include "auto_test_support.h" static void handle_conference_invite( const Tox_Event_Conference_Invite *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); const size_t length = tox_event_conference_invite_get_cookie_length(event); if (friend_number != UINT32_MAX) { Tox_Err_Conference_Join err; state->conference = tox_conference_join(autotox->tox, friend_number, cookie, length, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "attempting to join the conference returned with an error: %d", err); fprintf(stderr, "#%u accepted invite to conference %u\n", autotox->index, state->conference); } } static void handle_conference_connected( const Tox_Event_Conference_Connected *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; fprintf(stderr, "#%u connected to conference %u\n", autotox->index, state->conference); state->connected = true; } static void wait_connected(AutoTox *autotoxes, const AutoTox *autotox, uint32_t friendnumber) { do { iterate_all_wait(autotoxes, NUM_INVITE_MERGE_TOX, ITERATION_INTERVAL); } while (tox_friend_get_connection_status(autotox->tox, friendnumber, nullptr) == TOX_CONNECTION_NONE); } static void do_invite(AutoTox *autotoxes, AutoTox *inviter, AutoTox *invitee, uint32_t friendnum) { fprintf(stderr, "#%u inviting #%u\n", inviter->index, invitee->index); Tox_Err_Conference_Invite err; tox_conference_invite(inviter->tox, friendnum, ((State *)inviter->state)->conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "#%u attempting to invite #%u (friendnumber %u) returned with an error: %d", inviter->index, invitee->index, friendnum, err); do { iterate_all_wait(autotoxes, NUM_INVITE_MERGE_TOX, ITERATION_INTERVAL); } while (!((State *)invitee->state)->connected); } static bool group_complete(AutoTox *autotoxes) { int c = -1, size = 0; for (int i = 0; i < NUM_INVITE_MERGE_TOX; i++) { if (!autotoxes[i].alive) { continue; } const int ct = tox_conference_peer_count(autotoxes[i].tox, ((State *)autotoxes[i].state)->conference, nullptr); if (c == -1) { c = ct; } else if (c != ct) { return false; } ++size; } return (c == size); } static void wait_group_complete(AutoTox *autotoxes) { do { iterate_all_wait(autotoxes, NUM_INVITE_MERGE_TOX, ITERATION_INTERVAL); } while (!group_complete(autotoxes)); } static void conference_invite_merge_test(AutoTox *autotoxes) { // Test that an explicit invite between peers in different connected // components will cause a split group to merge for (int i = 0; i < NUM_INVITE_MERGE_TOX; i++) { tox_events_callback_conference_invite(autotoxes[i].dispatch, handle_conference_invite); tox_events_callback_conference_connected(autotoxes[i].dispatch, handle_conference_connected); } State *state2 = (State *)autotoxes[2].state; { // Create new conference, tox 2 is the founder. Tox_Err_Conference_New err; state2->conference = tox_conference_new(autotoxes[2].tox, &err); state2->connected = true; ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "attempting to create a new conference returned with an error: %d", err); fprintf(stderr, "Created conference: index=%u\n", state2->conference); } save_autotox(&autotoxes[2]); do_invite(autotoxes, &autotoxes[2], &autotoxes[1], 0); do_invite(autotoxes, &autotoxes[1], &autotoxes[0], 0); save_autotox(&autotoxes[1]); kill_autotox(&autotoxes[1]); do { iterate_all_wait(autotoxes, NUM_INVITE_MERGE_TOX, ITERATION_INTERVAL); } while (tox_conference_peer_count(autotoxes[2].tox, state2->conference, nullptr) != 1); do_invite(autotoxes, &autotoxes[2], &autotoxes[3], 1); do_invite(autotoxes, &autotoxes[3], &autotoxes[4], 1); kill_autotox(&autotoxes[2]); reload(&autotoxes[1]); uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(autotoxes[1].tox, public_key); tox_friend_add_norequest(autotoxes[3].tox, public_key, nullptr); tox_self_get_public_key(autotoxes[3].tox, public_key); tox_friend_add_norequest(autotoxes[1].tox, public_key, nullptr); wait_connected(autotoxes, &autotoxes[1], 2); do_invite(autotoxes, &autotoxes[1], &autotoxes[3], 2); fprintf(stderr, "Waiting for group to merge\n"); wait_group_complete(autotoxes); fprintf(stderr, "Group merged\n"); reload(&autotoxes[2]); wait_connected(autotoxes, &autotoxes[2], 0); do_invite(autotoxes, &autotoxes[2], &autotoxes[1], 0); fprintf(stderr, "Waiting for #2 to rejoin\n"); wait_group_complete(autotoxes); kill_autotox(&autotoxes[2]); wait_group_complete(autotoxes); reload(&autotoxes[2]); wait_connected(autotoxes, &autotoxes[2], 0); wait_connected(autotoxes, &autotoxes[1], 1); do_invite(autotoxes, &autotoxes[1], &autotoxes[2], 1); fprintf(stderr, "Waiting for #2 to rejoin\n"); wait_group_complete(autotoxes); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, NUM_INVITE_MERGE_TOX, conference_invite_merge_test, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/conference_peer_nick_test.c0000644060175106017510000001342714714247532021231 0ustar robin#include #include typedef struct State { bool self_online; bool friend_online; bool friend_in_group; bool joined; uint32_t conference; } State; #include "auto_test_support.h" static void handle_conference_invite( const Tox_Event_Conference_Invite *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); const Tox_Conference_Type type = tox_event_conference_invite_get_type(event); const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); const size_t length = tox_event_conference_invite_get_cookie_length(event); fprintf(stderr, "handle_conference_invite(#%u, %u, %d, uint8_t[%u], _)\n", autotox->index, friend_number, type, (unsigned)length); fprintf(stderr, "tox%u joining conference\n", autotox->index); Tox_Err_Conference_Join err; state->conference = tox_conference_join(autotox->tox, friend_number, cookie, length, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "attempting to join the conference returned with an error: %d", err); fprintf(stderr, "tox%u joined conference %u\n", autotox->index, state->conference); state->joined = true; } static void handle_peer_list_changed(const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const uint32_t conference_number = tox_event_conference_peer_list_changed_get_conference_number(event); fprintf(stderr, "handle_peer_list_changed(#%u, %u, _)\n", autotox->index, conference_number); Tox_Err_Conference_Peer_Query err; uint32_t const count = tox_conference_peer_count(autotox->tox, conference_number, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK, "failed to get conference peer count: err = %d", err); printf("tox%u has %u peers\n", autotox->index, count); state->friend_in_group = count == 2; } static void rebuild_peer_list(Tox *tox) { for (uint32_t conference_number = 0; conference_number < tox_conference_get_chatlist_size(tox); ++conference_number) { Tox_Err_Conference_Peer_Query err; uint32_t const count = tox_conference_peer_count(tox, conference_number, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK, "failed to get conference peer count for conference %u: err = %d", conference_number, err); for (uint32_t peer_number = 0; peer_number < count; peer_number++) { size_t size = tox_conference_peer_get_name_size(tox, conference_number, peer_number, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK, "failed to get conference peer %u's name size (conference = %u): err = %d", peer_number, conference_number, err); uint8_t *const name = (uint8_t *)malloc(size); ck_assert(name != nullptr); tox_conference_peer_get_name(tox, conference_number, peer_number, name, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_PEER_QUERY_OK, "failed to get conference peer %u's name (conference = %u): err = %d", peer_number, conference_number, err); free(name); } } } static void conference_peer_nick_test(AutoTox *autotoxes) { // Conference callbacks. tox_events_callback_conference_invite(autotoxes[0].dispatch, handle_conference_invite); tox_events_callback_conference_invite(autotoxes[1].dispatch, handle_conference_invite); tox_events_callback_conference_peer_list_changed(autotoxes[0].dispatch, handle_peer_list_changed); tox_events_callback_conference_peer_list_changed(autotoxes[1].dispatch, handle_peer_list_changed); // Set the names of the toxes. tox_self_set_name(autotoxes[0].tox, (const uint8_t *)"test-tox-0", 10, nullptr); tox_self_set_name(autotoxes[1].tox, (const uint8_t *)"test-tox-1", 10, nullptr); State *state[2]; state[0] = (State *)autotoxes[0].state; state[1] = (State *)autotoxes[1].state; { // Create new conference, tox0 is the founder. Tox_Err_Conference_New err; state[0]->conference = tox_conference_new(autotoxes[0].tox, &err); state[0]->joined = true; ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "attempting to create a new conference returned with an error: %d", err); fprintf(stderr, "Created conference: index=%u\n", state[0]->conference); } { // Invite friend. Tox_Err_Conference_Invite err; tox_conference_invite(autotoxes[0].tox, 0, state[0]->conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "attempting to invite a friend returned with an error: %d", err); fprintf(stderr, "tox0 invited tox1\n"); } fprintf(stderr, "Waiting for invitation to arrive and peers to be in the group\n"); do { iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } while (!state[0]->joined || !state[1]->joined || !state[0]->friend_in_group || !state[1]->friend_in_group); fprintf(stderr, "Running tox0, but not tox1, waiting for tox1 to drop out\n"); do { iterate_all_wait(autotoxes, 1, 1000); // Rebuild peer list after every iteration. rebuild_peer_list(autotoxes[0].tox); } while (state[0]->friend_in_group); fprintf(stderr, "Invitations accepted\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, conference_peer_nick_test, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/conference_simple_test.c0000644060175106017510000002324614714247532020563 0ustar robin#include #include #include "../testing/misc_tools.h" #include "../toxcore/tox.h" #include "../toxcore/tox_dispatch.h" #include "../toxcore/tox_events.h" #include "auto_test_support.h" #include "check_compat.h" typedef struct State { uint32_t id; Tox *tox; bool self_online; bool friend_online; bool invited_next; bool joined; uint32_t conference; bool received; uint32_t peers; } State; static void handle_self_connection_status(const Tox_Event_Self_Connection_Status *event, void *user_data) { State *state = (State *)user_data; const Tox_Connection connection_status = tox_event_self_connection_status_get_connection_status(event); fprintf(stderr, "self_connection_status(#%u, %d, _)\n", state->id, connection_status); state->self_online = connection_status != TOX_CONNECTION_NONE; } static void handle_friend_connection_status(const Tox_Event_Friend_Connection_Status *event, void *user_data) { State *state = (State *)user_data; const uint32_t friend_number = tox_event_friend_connection_status_get_friend_number(event); const Tox_Connection connection_status = tox_event_friend_connection_status_get_connection_status(event); fprintf(stderr, "handle_friend_connection_status(#%u, %u, %d, _)\n", state->id, friend_number, connection_status); state->friend_online = connection_status != TOX_CONNECTION_NONE; } static void handle_conference_invite(const Tox_Event_Conference_Invite *event, void *user_data) { State *state = (State *)user_data; const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); const Tox_Conference_Type type = tox_event_conference_invite_get_type(event); const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); const size_t length = tox_event_conference_invite_get_cookie_length(event); fprintf(stderr, "handle_conference_invite(#%u, %u, %d, uint8_t[%u], _)\n", state->id, friend_number, type, (unsigned)length); fprintf(stderr, "tox%u joining conference\n", state->id); { Tox_Err_Conference_Join err; state->conference = tox_conference_join(state->tox, friend_number, cookie, length, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "failed to join a conference: err = %d", err); fprintf(stderr, "tox%u Joined conference %u\n", state->id, state->conference); state->joined = true; } } static void handle_conference_message(const Tox_Event_Conference_Message *event, void *user_data) { State *state = (State *)user_data; const uint32_t conference_number = tox_event_conference_message_get_conference_number(event); const uint32_t peer_number = tox_event_conference_message_get_peer_number(event); const Tox_Message_Type type = tox_event_conference_message_get_type(event); const uint8_t *message = tox_event_conference_message_get_message(event); const size_t length = tox_event_conference_message_get_message_length(event); fprintf(stderr, "handle_conference_message(#%u, %u, %u, %d, uint8_t[%u], _)\n", state->id, conference_number, peer_number, type, (unsigned)length); fprintf(stderr, "tox%u got message: %s\n", state->id, (const char *)message); state->received = true; } static void handle_conference_peer_list_changed(const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) { State *state = (State *)user_data; const uint32_t conference_number = tox_event_conference_peer_list_changed_get_conference_number(event); fprintf(stderr, "handle_conference_peer_list_changed(#%u, %u, _)\n", state->id, conference_number); Tox_Err_Conference_Peer_Query err; uint32_t count = tox_conference_peer_count(state->tox, conference_number, &err); if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { fprintf(stderr, "ERROR: %d\n", err); exit(EXIT_FAILURE); } fprintf(stderr, "tox%u has %u peers online\n", state->id, count); state->peers = count; } static void handle_conference_connected(const Tox_Event_Conference_Connected *event, void *user_data) { State *state = (State *)user_data; // We're tox2, so now we invite tox3. if (state->id == 2 && !state->invited_next) { Tox_Err_Conference_Invite err; tox_conference_invite(state->tox, 1, state->conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox2 failed to invite tox3: err = %d", err); state->invited_next = true; fprintf(stderr, "tox2 invited tox3\n"); } } static void iterate_one( Tox *tox, State *state, const Tox_Dispatch *dispatch) { Tox_Err_Events_Iterate err; Tox_Events *events = tox_events_iterate(tox, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch, events, state); tox_events_free(events); } static void iterate3_wait( State *state1, State *state2, State *state3, const Tox_Dispatch *dispatch, int interval) { iterate_one(state1->tox, state1, dispatch); iterate_one(state2->tox, state2, dispatch); iterate_one(state3->tox, state3, dispatch); c_sleep(interval); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); State state1 = {1}; State state2 = {2}; State state3 = {3}; // Create toxes. state1.tox = tox_new_log(nullptr, nullptr, &state1.id); state2.tox = tox_new_log(nullptr, nullptr, &state2.id); state3.tox = tox_new_log(nullptr, nullptr, &state3.id); tox_events_init(state1.tox); tox_events_init(state2.tox); tox_events_init(state3.tox); // tox1 <-> tox2, tox2 <-> tox3 uint8_t key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(state2.tox, key); tox_friend_add_norequest(state1.tox, key, nullptr); // tox1 -> tox2 tox_self_get_public_key(state1.tox, key); tox_friend_add_norequest(state2.tox, key, nullptr); // tox2 -> tox1 tox_self_get_public_key(state3.tox, key); tox_friend_add_norequest(state2.tox, key, nullptr); // tox2 -> tox3 tox_self_get_public_key(state2.tox, key); tox_friend_add_norequest(state3.tox, key, nullptr); // tox3 -> tox2 printf("bootstrapping tox2 and tox3 off tox1\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(state1.tox, dht_key); const uint16_t dht_port = tox_self_get_udp_port(state1.tox, nullptr); tox_bootstrap(state2.tox, "localhost", dht_port, dht_key, nullptr); tox_bootstrap(state3.tox, "localhost", dht_port, dht_key, nullptr); Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); // Connection callbacks. tox_events_callback_self_connection_status(dispatch, handle_self_connection_status); tox_events_callback_friend_connection_status(dispatch, handle_friend_connection_status); // Conference callbacks. tox_events_callback_conference_invite(dispatch, handle_conference_invite); tox_events_callback_conference_connected(dispatch, handle_conference_connected); tox_events_callback_conference_message(dispatch, handle_conference_message); tox_events_callback_conference_peer_list_changed(dispatch, handle_conference_peer_list_changed); // Wait for self connection. fprintf(stderr, "Waiting for toxes to come online\n"); do { iterate3_wait(&state1, &state2, &state3, dispatch, 100); } while (!state1.self_online || !state2.self_online || !state3.self_online); fprintf(stderr, "Toxes are online\n"); // Wait for friend connection. fprintf(stderr, "Waiting for friends to connect\n"); do { iterate3_wait(&state1, &state2, &state3, dispatch, 100); } while (!state1.friend_online || !state2.friend_online || !state3.friend_online); fprintf(stderr, "Friends are connected\n"); { // Create new conference, tox1 is the founder. Tox_Err_Conference_New err; state1.conference = tox_conference_new(state1.tox, &err); state1.joined = true; ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "failed to create a conference: err = %d", err); fprintf(stderr, "Created conference: id = %u\n", state1.conference); } { // Invite friend. Tox_Err_Conference_Invite err; tox_conference_invite(state1.tox, 0, state1.conference, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "failed to invite a friend: err = %d", err); state1.invited_next = true; fprintf(stderr, "tox1 invited tox2\n"); } fprintf(stderr, "Waiting for invitation to arrive\n"); do { iterate3_wait(&state1, &state2, &state3, dispatch, 100); } while (!state1.joined || !state2.joined || !state3.joined); fprintf(stderr, "Invitations accepted\n"); fprintf(stderr, "Waiting for peers to come online\n"); do { iterate3_wait(&state1, &state2, &state3, dispatch, 100); } while (state1.peers == 0 || state2.peers == 0 || state3.peers == 0); fprintf(stderr, "All peers are online\n"); { fprintf(stderr, "tox1 sends a message to the group: \"hello!\"\n"); Tox_Err_Conference_Send_Message err; tox_conference_send_message(state1.tox, state1.conference, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"hello!", 7, &err); if (err != TOX_ERR_CONFERENCE_SEND_MESSAGE_OK) { fprintf(stderr, "ERROR: %d\n", err); exit(EXIT_FAILURE); } } fprintf(stderr, "Waiting for messages to arrive\n"); do { iterate3_wait(&state1, &state2, &state3, dispatch, 100); c_sleep(100); } while (!state2.received || !state3.received); fprintf(stderr, "Messages received. Test complete.\n"); tox_dispatch_free(dispatch); tox_kill(state3.tox); tox_kill(state2.tox); tox_kill(state1.tox); return 0; } c-toxcore-0.2.20/auto_tests/conference_test.c0000644060175106017510000003625514714247532017216 0ustar robin/* Auto Tests: Conferences. */ #include #include #include #include #include "../toxcore/util.h" #include "check_compat.h" #define NUM_GROUP_TOX 16 #define NUM_DISCONNECT 8 #define GROUP_MESSAGE "Install Gentoo" #define NAMELEN 9 #define NAME_FORMAT_STR "Tox #%4u" #define NEW_NAME_FORMAT_STR "New #%4u" typedef struct State { bool invited_next; } State; #include "auto_test_support.h" static void handle_self_connection_status( Tox *tox, Tox_Connection connection_status, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; if (connection_status != TOX_CONNECTION_NONE) { printf("tox #%u: is now connected\n", autotox->index); } else { printf("tox #%u: is now disconnected\n", autotox->index); } } static void handle_friend_connection_status( Tox *tox, uint32_t friendnumber, Tox_Connection connection_status, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; if (connection_status != TOX_CONNECTION_NONE) { printf("tox #%u: is now connected to friend %u\n", autotox->index, friendnumber); } else { printf("tox #%u: is now disconnected from friend %u\n", autotox->index, friendnumber); } } static void handle_conference_invite( Tox *tox, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *data, size_t length, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; ck_assert_msg(type == TOX_CONFERENCE_TYPE_TEXT, "tox #%u: wrong conference type: %d", autotox->index, type); Tox_Err_Conference_Join err; uint32_t g_num = tox_conference_join(autotox->tox, friendnumber, data, length, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_JOIN_OK, "tox #%u: error joining group: %d", autotox->index, err); ck_assert_msg(g_num == 0, "tox #%u: group number was not 0", autotox->index); // Try joining again. We should only be allowed to join once. tox_conference_join(autotox->tox, friendnumber, data, length, &err); ck_assert_msg(err != TOX_ERR_CONFERENCE_JOIN_OK, "tox #%u: joining groupchat twice should be impossible.", autotox->index); } static void handle_conference_connected( Tox *tox, uint32_t conference_number, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; if (state->invited_next || tox_self_get_friend_list_size(autotox->tox) <= 1) { return; } Tox_Err_Conference_Invite err; tox_conference_invite(autotox->tox, 1, 0, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", autotox->index, err); printf("tox #%u: invited next friend\n", autotox->index); state->invited_next = true; } static uint32_t num_recv; static void handle_conference_message( Tox *tox, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type, const uint8_t *message, size_t length, void *user_data) { if (length == (sizeof(GROUP_MESSAGE) - 1) && memcmp(message, GROUP_MESSAGE, sizeof(GROUP_MESSAGE) - 1) == 0) { ++num_recv; } } static bool toxes_are_disconnected_from_group(uint32_t tox_count, AutoTox *autotoxes, const bool *disconnected) { uint32_t num_disconnected = 0; for (uint32_t i = 0; i < tox_count; ++i) { num_disconnected += disconnected[i]; } for (uint32_t i = 0; i < tox_count; i++) { if (disconnected[i]) { continue; } if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) > tox_count - num_disconnected) { return false; } } return true; } static void disconnect_toxes(uint32_t tox_count, AutoTox *autotoxes, const bool *disconnect, const bool *exclude) { /* Fake a network outage for a set of peers D by iterating only the other * peers D' until the connections time out according to D', then iterating * only D until the connections time out according to D. */ VLA(bool, disconnect_now, tox_count); bool invert = false; do { for (uint32_t i = 0; i < tox_count; ++i) { disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]); } do { for (uint32_t i = 0; i < tox_count; ++i) { if (!disconnect_now[i]) { tox_iterate(autotoxes[i].tox, &autotoxes[i]); autotoxes[i].clock += 1000; } } c_sleep(20); } while (!toxes_are_disconnected_from_group(tox_count, autotoxes, disconnect_now)); invert = !invert; } while (invert); } static bool all_connected_to_group(uint32_t tox_count, AutoTox *autotoxes) { for (uint32_t i = 0; i < tox_count; i++) { if (tox_conference_peer_count(autotoxes[i].tox, 0, nullptr) < tox_count) { return false; } } return true; } static bool names_propagated(uint32_t tox_count, AutoTox *autotoxes) { for (uint32_t i = 0; i < tox_count; ++i) { for (uint32_t j = 0; j < tox_count; ++j) { const size_t len = tox_conference_peer_get_name_size(autotoxes[i].tox, 0, j, nullptr); if (len != NAMELEN) { return false; } } } return true; } /** * returns a random index at which a list of booleans is false * (some such index is required to exist) */ static uint32_t random_false_index(const Random *rng, const bool *list, const uint32_t length) { uint32_t index; do { index = random_u32(rng) % length; } while (list[index]); return index; } static void run_conference_tests(AutoTox *autotoxes) { const Random *rng = os_random(); ck_assert(rng != nullptr); /* disabling name change propagation check for now, as it occasionally * fails due to disconnections too short to trigger freezing */ const bool check_name_change_propagation = false; /* each peer should freeze at least its two friends, but freezing more * should not be necessary */ const uint32_t max_frozen = max_u32(2, NUM_DISCONNECT / 2); printf("restricting number of frozen peers to %u\n", max_frozen); for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { Tox_Err_Conference_Set_Max_Offline err; tox_conference_set_max_offline(autotoxes[i].tox, 0, max_frozen, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK, "tox #%u failed to set max offline: err = %d", autotoxes[i].index, err); } printf("letting random toxes timeout\n"); bool disconnected[NUM_GROUP_TOX] = {0}; bool restarting[NUM_GROUP_TOX] = {0}; ck_assert(NUM_DISCONNECT < NUM_GROUP_TOX); for (uint32_t i = 0; i < NUM_DISCONNECT; ++i) { uint32_t disconnect = random_false_index(rng, disconnected, NUM_GROUP_TOX); disconnected[disconnect] = true; if (i < NUM_DISCONNECT / 2) { restarting[disconnect] = true; printf("Restarting #%u\n", autotoxes[disconnect].index); } else { printf("Disconnecting #%u\n", autotoxes[disconnect].index); } } uint8_t *save[NUM_GROUP_TOX]; size_t save_size[NUM_GROUP_TOX]; for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { if (restarting[i]) { save_size[i] = tox_get_savedata_size(autotoxes[i].tox); ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]); save[i] = (uint8_t *)malloc(save_size[i]); ck_assert_msg(save[i] != nullptr, "malloc failed"); tox_get_savedata(autotoxes[i].tox, save[i]); tox_kill(autotoxes[i].tox); } } disconnect_toxes(NUM_GROUP_TOX, autotoxes, disconnected, restarting); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { if (restarting[i]) { struct Tox_Options *const options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, save[i], save_size[i]); autotoxes[i].tox = tox_new_log(options, nullptr, &autotoxes[i].index); ck_assert(autotoxes[i].tox != nullptr); tox_options_free(options); free(save[i]); set_mono_time_callback(&autotoxes[i]); tox_conference_set_max_offline(autotoxes[i].tox, 0, max_frozen, nullptr); } } if (check_name_change_propagation) { printf("changing names\n"); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { char name[NAMELEN + 1]; snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, autotoxes[i].index); tox_self_set_name(autotoxes[i].tox, (const uint8_t *)name, NAMELEN, nullptr); } } for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { const uint32_t num_frozen = tox_conference_offline_peer_count(autotoxes[i].tox, 0, nullptr); ck_assert_msg(num_frozen <= max_frozen, "tox #%u has too many offline peers: %u\n", autotoxes[i].index, num_frozen); } printf("reconnecting toxes\n"); do { iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); } while (!all_connected_to_group(NUM_GROUP_TOX, autotoxes)); printf("running conference tests\n"); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { tox_callback_conference_message(autotoxes[i].tox, &handle_conference_message); iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); } Tox_Err_Conference_Send_Message err; ck_assert_msg( tox_conference_send_message( autotoxes[random_u32(rng) % NUM_GROUP_TOX].tox, 0, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)GROUP_MESSAGE, sizeof(GROUP_MESSAGE) - 1, &err) != 0, "failed to send group message"); ck_assert_msg( err == TOX_ERR_CONFERENCE_SEND_MESSAGE_OK, "failed to send group message"); num_recv = 0; for (uint8_t j = 0; j < NUM_GROUP_TOX * 2; ++j) { iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); } ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages"); if (check_name_change_propagation) { for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { for (uint32_t j = 0; j < NUM_GROUP_TOX; ++j) { uint8_t name[NAMELEN]; tox_conference_peer_get_name(autotoxes[i].tox, 0, j, name, nullptr); /* Note the toxes will have been reordered */ ck_assert_msg(memcmp(name, "New", 3) == 0, "name of #%u according to #%u not updated", autotoxes[j].index, autotoxes[i].index); } } } for (uint32_t k = NUM_GROUP_TOX; k != 0 ; --k) { tox_conference_delete(autotoxes[k - 1].tox, 0, nullptr); for (uint8_t j = 0; j < 10 || j < NUM_GROUP_TOX; ++j) { iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); } for (uint32_t i = 0; i < k - 1; ++i) { uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, nullptr); ck_assert_msg(peer_count == (k - 1), "\n\tBad number of group peers (post check)." "\n\t\t\tExpected: %u but tox_instance(%u) only has: %u\n\n", k - 1, i, (unsigned)peer_count); } } } static void test_many_group(AutoTox *autotoxes) { const time_t test_start_time = time(nullptr); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { tox_callback_self_connection_status(autotoxes[i].tox, &handle_self_connection_status); tox_callback_friend_connection_status(autotoxes[i].tox, &handle_friend_connection_status); tox_callback_conference_invite(autotoxes[i].tox, &handle_conference_invite); tox_callback_conference_connected(autotoxes[i].tox, &handle_conference_connected); char name[NAMELEN + 1]; snprintf(name, NAMELEN + 1, NAME_FORMAT_STR, autotoxes[i].index); tox_self_set_name(autotoxes[i].tox, (const uint8_t *)name, NAMELEN, nullptr); } ck_assert_msg(tox_conference_new(autotoxes[0].tox, nullptr) != UINT32_MAX, "failed to create group"); printf("tox #%u: inviting its first friend\n", autotoxes[0].index); ck_assert_msg(tox_conference_invite(autotoxes[0].tox, 0, 0, nullptr) != 0, "failed to invite friend"); ((State *)autotoxes[0].state)->invited_next = true; ck_assert_msg(tox_conference_set_title(autotoxes[0].tox, 0, (const uint8_t *)"Gentoo", sizeof("Gentoo") - 1, nullptr) != 0, "failed to set group title"); printf("waiting for invitations to be made\n"); uint32_t invited_count = 0; do { iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); invited_count = 0; for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { invited_count += ((State *)autotoxes[i].state)->invited_next; } } while (invited_count != NUM_GROUP_TOX - 1); uint64_t pregroup_clock = autotoxes[0].clock; printf("waiting for all toxes to be in the group\n"); uint32_t fully_connected_count = 0; do { fully_connected_count = 0; printf("current peer counts: ["); iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { Tox_Err_Conference_Peer_Query err; uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, &err); if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { peer_count = 0; } fully_connected_count += peer_count == NUM_GROUP_TOX; if (i != 0) { printf(", "); } printf("%u", peer_count); } printf("]\n"); fflush(stdout); } while (fully_connected_count != NUM_GROUP_TOX); for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) { uint32_t peer_count = tox_conference_peer_count(autotoxes[i].tox, 0, nullptr); ck_assert_msg(peer_count == NUM_GROUP_TOX, "\n\tBad number of group peers (pre check)." "\n\t\t\tExpected: %d but tox_instance(%u) only has: %u\n\n", NUM_GROUP_TOX, i, (unsigned)peer_count); uint8_t title[2048]; size_t ret = tox_conference_get_title_size(autotoxes[i].tox, 0, nullptr); ck_assert_msg(ret == sizeof("Gentoo") - 1, "Wrong title length"); tox_conference_get_title(autotoxes[i].tox, 0, title, nullptr); ck_assert_msg(memcmp("Gentoo", title, ret) == 0, "Wrong title"); } printf("waiting for names to propagate\n"); do { iterate_all_wait(autotoxes, NUM_GROUP_TOX, ITERATION_INTERVAL); } while (!names_propagated(NUM_GROUP_TOX, autotoxes)); printf("group connected, took %d seconds\n", (int)((autotoxes[0].clock - pregroup_clock) / 1000)); run_conference_tests(autotoxes); printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time)); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; options.events = false; run_auto_test(nullptr, NUM_GROUP_TOX, test_many_group, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/conference_two_test.c0000644060175106017510000000150214714247532020072 0ustar robin// This test checks that we can create two conferences and quit properly. // // This test triggers a different code path than if we only allocate a single // conference. This is the simplest test possible that triggers it. #include "../testing/misc_tools.h" #include "../toxcore/tox.h" #include "auto_test_support.h" #include "check_compat.h" int main(void) { // Create toxes. uint32_t id = 1; Tox *tox1 = tox_new_log(nullptr, nullptr, &id); // Create two conferences and then exit. Tox_Err_Conference_New err; tox_conference_new(tox1, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "failed to create conference 1: %d", err); tox_conference_new(tox1, &err); ck_assert_msg(err == TOX_ERR_CONFERENCE_NEW_OK, "failed to create conference 2: %d", err); tox_kill(tox1); return 0; } c-toxcore-0.2.20/auto_tests/crypto_test.c0000644060175106017510000003142514714247532016421 0ustar robin#include #include #include #include "../testing/misc_tools.h" #include "../toxcore/crypto_core.h" #include "../toxcore/net_crypto.h" #include "check_compat.h" static void rand_bytes(const Random *rng, uint8_t *b, size_t blen) { for (size_t i = 0; i < blen; i++) { b[i] = random_u08(rng); } } // These test vectors are from libsodium's test suite static const uint8_t alicesk[32] = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a }; static const uint8_t bobpk[32] = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f }; static const uint8_t test_nonce[24] = { 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37 }; static const uint8_t test_m[131] = { 0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16, 0xeb, 0xeb, 0x0c, 0x7b, 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4, 0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf, 0x33, 0xbd, 0x75, 0x1a, 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29, 0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce, 0x31, 0x4a, 0xdb, 0x31, 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d, 0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a, 0xd6, 0xb1, 0x31, 0x8a, 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde, 0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c, 0x60, 0x90, 0x2e, 0x52, 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40, 0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05 }; static const uint8_t test_c[147] = { 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9, 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, 0xe3, 0x55, 0xa5 }; static void test_known(void) { uint8_t c[147]; uint8_t m[131]; ck_assert_msg(sizeof(c) == sizeof(m) + CRYPTO_MAC_SIZE * sizeof(uint8_t), "cyphertext should be CRYPTO_MAC_SIZE bytes longer than plaintext"); ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed"); ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed"); const uint16_t clen = encrypt_data(bobpk, alicesk, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c); ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector"); ck_assert_msg(clen == sizeof(c) / sizeof(uint8_t), "wrong ciphertext length"); const uint16_t mlen = decrypt_data(bobpk, alicesk, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m); ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector"); ck_assert_msg(mlen == sizeof(m) / sizeof(uint8_t), "wrong plaintext length"); } static void test_fast_known(void) { uint8_t k[CRYPTO_SHARED_KEY_SIZE]; uint8_t c[147]; uint8_t m[131]; encrypt_precompute(bobpk, alicesk, k); ck_assert_msg(sizeof(c) == sizeof(m) + CRYPTO_MAC_SIZE * sizeof(uint8_t), "cyphertext should be CRYPTO_MAC_SIZE bytes longer than plaintext"); ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed"); ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed"); const uint16_t clen = encrypt_data_symmetric(k, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c); ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector"); ck_assert_msg(clen == sizeof(c) / sizeof(uint8_t), "wrong ciphertext length"); const uint16_t mlen = decrypt_data_symmetric(k, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m); ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector"); ck_assert_msg(mlen == sizeof(m) / sizeof(uint8_t), "wrong plaintext length"); } static void test_endtoend(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); // Test 100 random messages and keypairs for (uint8_t testno = 0; testno < 100; testno++) { uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t sk1[CRYPTO_SECRET_KEY_SIZE]; uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t sk2[CRYPTO_SECRET_KEY_SIZE]; uint8_t k1[CRYPTO_SHARED_KEY_SIZE]; uint8_t k2[CRYPTO_SHARED_KEY_SIZE]; uint8_t n[CRYPTO_NONCE_SIZE]; enum { M_SIZE = 50 }; uint8_t m[M_SIZE]; uint8_t c1[sizeof(m) + CRYPTO_MAC_SIZE]; uint8_t c2[sizeof(m) + CRYPTO_MAC_SIZE]; uint8_t c3[sizeof(m) + CRYPTO_MAC_SIZE]; uint8_t c4[sizeof(m) + CRYPTO_MAC_SIZE]; uint8_t m1[sizeof(m)]; uint8_t m2[sizeof(m)]; uint8_t m3[sizeof(m)]; uint8_t m4[sizeof(m)]; //Generate random message (random length from 10 to 50) const uint16_t mlen = (random_u32(rng) % (M_SIZE - 10)) + 10; rand_bytes(rng, m, mlen); rand_bytes(rng, n, CRYPTO_NONCE_SIZE); //Generate keypairs crypto_new_keypair(rng, pk1, sk1); crypto_new_keypair(rng, pk2, sk2); //Precompute shared keys encrypt_precompute(pk2, sk1, k1); encrypt_precompute(pk1, sk2, k2); ck_assert_msg(memcmp(k1, k2, CRYPTO_SHARED_KEY_SIZE) == 0, "encrypt_precompute: bad"); //Encrypt all four ways const uint16_t c1len = encrypt_data(pk2, sk1, n, m, mlen, c1); const uint16_t c2len = encrypt_data(pk1, sk2, n, m, mlen, c2); const uint16_t c3len = encrypt_data_symmetric(k1, n, m, mlen, c3); const uint16_t c4len = encrypt_data_symmetric(k2, n, m, mlen, c4); ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, "cyphertext lengths differ"); ck_assert_msg(c1len == mlen + (uint16_t)CRYPTO_MAC_SIZE, "wrong cyphertext length"); ck_assert_msg(memcmp(c1, c2, c1len) == 0 && memcmp(c1, c3, c1len) == 0 && memcmp(c1, c4, c1len) == 0, "crypertexts differ"); //Decrypt all four ways const uint16_t m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1); const uint16_t m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2); const uint16_t m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3); const uint16_t m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4); ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, "decrypted text lengths differ"); ck_assert_msg(m1len == mlen, "wrong decrypted text length"); ck_assert_msg(memcmp(m1, m2, mlen) == 0 && memcmp(m1, m3, mlen) == 0 && memcmp(m1, m4, mlen) == 0, "decrypted texts differ"); ck_assert_msg(memcmp(m1, m, mlen) == 0, "wrong decrypted text"); } } static void test_large_data(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t k[CRYPTO_SHARED_KEY_SIZE]; uint8_t n[CRYPTO_NONCE_SIZE]; const size_t m1_size = MAX_CRYPTO_PACKET_SIZE - CRYPTO_MAC_SIZE; uint8_t *m1 = (uint8_t *)malloc(m1_size); uint8_t *c1 = (uint8_t *)malloc(m1_size + CRYPTO_MAC_SIZE); uint8_t *m1prime = (uint8_t *)malloc(m1_size); const size_t m2_size = MAX_CRYPTO_PACKET_SIZE - CRYPTO_MAC_SIZE; uint8_t *m2 = (uint8_t *)malloc(m2_size); uint8_t *c2 = (uint8_t *)malloc(m2_size + CRYPTO_MAC_SIZE); ck_assert(m1 != nullptr && c1 != nullptr && m1prime != nullptr && m2 != nullptr && c2 != nullptr); //Generate random messages rand_bytes(rng, m1, m1_size); rand_bytes(rng, m2, m2_size); rand_bytes(rng, n, CRYPTO_NONCE_SIZE); //Generate key rand_bytes(rng, k, CRYPTO_SHARED_KEY_SIZE); const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1); const uint16_t c2len = encrypt_data_symmetric(k, n, m2, m2_size, c2); ck_assert_msg(c1len == m1_size + CRYPTO_MAC_SIZE, "could not encrypt"); ck_assert_msg(c2len == m2_size + CRYPTO_MAC_SIZE, "could not encrypt"); const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime); ck_assert_msg(m1plen == m1_size, "decrypted text lengths differ"); ck_assert_msg(memcmp(m1prime, m1, m1_size) == 0, "decrypted texts differ"); free(c2); free(m2); free(m1prime); free(c1); free(m1); } static void test_large_data_symmetric(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t k[CRYPTO_SYMMETRIC_KEY_SIZE]; uint8_t n[CRYPTO_NONCE_SIZE]; const size_t m1_size = 16 * 16 * 16; uint8_t *m1 = (uint8_t *)malloc(m1_size); uint8_t *c1 = (uint8_t *)malloc(m1_size + CRYPTO_MAC_SIZE); uint8_t *m1prime = (uint8_t *)malloc(m1_size); ck_assert(m1 != nullptr && c1 != nullptr && m1prime != nullptr); //Generate random messages rand_bytes(rng, m1, m1_size); rand_bytes(rng, n, CRYPTO_NONCE_SIZE); //Generate key new_symmetric_key(rng, k); const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1); ck_assert_msg(c1len == m1_size + CRYPTO_MAC_SIZE, "could not encrypt data"); const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime); ck_assert_msg(m1plen == m1_size, "decrypted text lengths differ"); ck_assert_msg(memcmp(m1prime, m1, m1_size) == 0, "decrypted texts differ"); free(m1prime); free(c1); free(m1); } static void test_very_large_data(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const uint8_t nonce[CRYPTO_NONCE_SIZE] = {0}; uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t sk[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, pk, sk); // 100 MiB of data (all zeroes, doesn't matter what's inside). const uint32_t plain_size = 100 * 1024 * 1024; uint8_t *plain = (uint8_t *)malloc(plain_size); uint8_t *encrypted = (uint8_t *)malloc(plain_size + CRYPTO_MAC_SIZE); ck_assert(plain != nullptr); ck_assert(encrypted != nullptr); encrypt_data(pk, sk, nonce, plain, plain_size, encrypted); free(encrypted); free(plain); } static void increment_nonce_number_cmp(uint8_t *nonce, uint32_t num) { uint32_t num1 = 0; memcpy(&num1, nonce + (CRYPTO_NONCE_SIZE - sizeof(num1)), sizeof(num1)); num1 = net_ntohl(num1); uint32_t num2 = num + num1; if (num2 < num1) { for (uint16_t i = CRYPTO_NONCE_SIZE - sizeof(num1); i != 0; --i) { ++nonce[i - 1]; if (nonce[i - 1] != 0) { break; } } } num2 = net_htonl(num2); memcpy(nonce + (CRYPTO_NONCE_SIZE - sizeof(num2)), &num2, sizeof(num2)); } static void test_increment_nonce(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t n[CRYPTO_NONCE_SIZE]; for (uint32_t i = 0; i < CRYPTO_NONCE_SIZE; ++i) { n[i] = random_u08(rng); } uint8_t n1[CRYPTO_NONCE_SIZE]; memcpy(n1, n, CRYPTO_NONCE_SIZE); for (uint32_t i = 0; i < (1 << 18); ++i) { increment_nonce_number_cmp(n, 1); increment_nonce(n1); ck_assert_msg(memcmp(n, n1, CRYPTO_NONCE_SIZE) == 0, "Bad increment_nonce function"); } for (uint32_t i = 0; i < (1 << 18); ++i) { const uint32_t r = random_u32(rng); increment_nonce_number_cmp(n, r); increment_nonce_number(n1, r); ck_assert_msg(memcmp(n, n1, CRYPTO_NONCE_SIZE) == 0, "Bad increment_nonce_number function"); } } static void test_memzero(void) { uint8_t src[sizeof(test_c)]; memcpy(src, test_c, sizeof(test_c)); crypto_memzero(src, sizeof(src)); for (size_t i = 0; i < sizeof(src); i++) { ck_assert_msg(src[i] == 0, "Memory is not zeroed"); } } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_known(); test_fast_known(); test_endtoend(); /* waiting up to 15 seconds */ test_large_data(); test_large_data_symmetric(); test_very_large_data(); test_increment_nonce(); test_memzero(); return 0; } c-toxcore-0.2.20/auto_tests/data/0000755060175106017510000000000014714247532014602 5ustar robinc-toxcore-0.2.20/auto_tests/data/save.tox.big0000644060175106017510000001062714714247532017042 0ustar robinDLv,}v驓<mocZB54>*q‰ Ҕ )~gnH VdH}1˚#bۙ sG*QՂ&ſ[kIFLf0xs,:a #fSWPb34l<9ٓ&|w = OfۄX6sY. i@Stɴbq6I6@;QQZT%-=ͣ" aC6 4%VJ+_eivxdJg66l~r$죐j&W{MF-X.4*0zݩف^~-2(O>iObg6HzU:yu0@?Q] S̙noOfۄX6sY. i@Stɴbqշ0bNNdpmIXkDeOL˞vOtq 6n?L]7.D2e5uƼ?*tNSҪe0& =p'MڌgfE𖂥"|ug (yz<||eS WKӸM@5A$Ifi {6HzUڐC*N"-4m7(!4nOٞe%cvŖ/Y_ 6I6@;QQZT%-=ͣ" aC6WKӸM@5A$Ifi {E𖂥"|ug (yz<||eS !4nOٞe%cvŖ/Y_ 6HzUڐC*N"-4m7(շ0bNNdpmIXkDeOL˞vOtNSҪe0& =p'Mڌgftq 6n?L]7.D2e5uƼ?*nmPw~f%B JTAdd me.5name Hello World 8  4%VJ+_eivxdJgOfۄX6sY. i@Stɴbqtq 6n?L]7.D2e5uƼ?*6HzUڐC*N"-4m7(!4nOٞe%cvŖ/Y_ N/>bFيVeₔhrC{14*0zݩف^~-2(O>iObg[i*UːOT ` ~fԌflc-toxcore-0.2.20/auto_tests/data/save.tox.little0000644060175106017510000001067614714247532017602 0ustar robinDLv,}v驓<mocZB54>*q‰ Ҕ )~ǂh% qG;rJ* (6=6HzU<\Q?L"~fjBbKr *Э L"+]*:9G>зNkZnٚwZ. jhO^vշEoռ4q)~43jKM9"JϏ+y?bD1O-"o|EԿi7M. B޵5ʼ{ip[ ?p{6+&^k1S^N޾a2i'9yBG/V=9#k_m8^LJw 8Bt3^WDr>/\[UTD6rq1|S<ZJFN6K#԰rA` GPQ)(E>$/60`?SR/b}/U!酃z(yu>}+зNk6HzU<\Q?L"~fjBbKr ZnٚwZ. jhO^vշEoռ4q)~XMg҉+I?gS5X!+.Gҥ %MYAY; +0p~'B3C:6T* Q T{wٚ~#tsv.YSR/b}/U!酃z(yu>}+$/60`?6rq1|S<ZJFNi'9yBG/V=9#k_m8^LJw 8Bt3^WDr>/\[UTDnmPw~f%B JTAdd me.5name Hello World 8  ?p{6+&^k1S^N޾a2ǂh% qG;rJ* (6=*Э L"+]*:9G>зNk6HzU<\Q?L"~fjBbKr 6rq1|S<ZJFN.f8wiSŇ2j`\"o|EԿi7M. B޵5ʼ{ip[43jKM9"JϏ+y?bD1O-c-toxcore-0.2.20/auto_tests/dht_getnodes_api_test.c0000644060175106017510000001112014714247532020367 0ustar robin/** * This autotest creates a small local DHT and makes sure that each peer can crawl * the entire DHT using the DHT getnodes api functions. */ #include #include #include #include #include "../toxcore/tox.h" #include "../toxcore/tox_private.h" #include "auto_test_support.h" #include "check_compat.h" #define NUM_TOXES 30 typedef struct Dht_Node { uint8_t public_key[TOX_DHT_NODE_PUBLIC_KEY_SIZE]; char ip[TOX_DHT_NODE_IP_STRING_SIZE]; uint16_t port; } Dht_Node; typedef struct State { Dht_Node **nodes; size_t num_nodes; uint8_t **public_key_list; } State; static void free_nodes(Dht_Node **nodes, size_t num_nodes) { for (size_t i = 0; i < num_nodes; ++i) { free(nodes[i]); } free(nodes); } static bool node_crawled(Dht_Node **nodes, size_t num_nodes, const uint8_t *public_key) { for (size_t i = 0; i < num_nodes; ++i) { if (memcmp(nodes[i]->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE) == 0) { return true; } } return false; } static bool all_nodes_crawled(const AutoTox *autotoxes, uint32_t num_toxes, uint8_t **public_key_list) { for (uint32_t i = 0; i < num_toxes; ++i) { const State *state = (const State *)autotoxes[i].state; // make sure each peer has crawled the correct number of nodes if (state->num_nodes < num_toxes) { return false; } } for (uint32_t i = 0; i < num_toxes; ++i) { const State *state = (const State *)autotoxes[i].state; // make sure each peer has the full list of public keys for (uint32_t j = 0; j < num_toxes; ++j) { if (!node_crawled(state->nodes, state->num_nodes, public_key_list[j])) { return false; } } } return true; } static void getnodes_response_cb(const Tox_Event_Dht_Get_Nodes_Response *event, void *user_data) { ck_assert(user_data != nullptr); AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const uint8_t *public_key = tox_event_dht_get_nodes_response_get_public_key(event); const char *ip = (const char *)tox_event_dht_get_nodes_response_get_ip(event); const uint16_t port = tox_event_dht_get_nodes_response_get_port(event); if (node_crawled(state->nodes, state->num_nodes, public_key)) { return; } ck_assert(state->num_nodes < NUM_TOXES); Dht_Node *node = (Dht_Node *)calloc(1, sizeof(Dht_Node)); ck_assert(node != nullptr); memcpy(node->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE); snprintf(node->ip, sizeof(node->ip), "%s", ip); node->port = port; state->nodes[state->num_nodes] = node; ++state->num_nodes; // ask new node to give us their close nodes to every public key for (size_t i = 0; i < NUM_TOXES; ++i) { tox_dht_get_nodes(autotox->tox, public_key, ip, port, state->public_key_list[i], nullptr); } } static void test_dht_getnodes(AutoTox *autotoxes) { ck_assert(NUM_TOXES >= 2); uint8_t **public_key_list = (uint8_t **)calloc(NUM_TOXES, sizeof(uint8_t *)); ck_assert(public_key_list != nullptr); for (size_t i = 0; i < NUM_TOXES; ++i) { State *state = (State *)autotoxes[i].state; state->nodes = (Dht_Node **)calloc(NUM_TOXES, sizeof(Dht_Node *)); ck_assert(state->nodes != nullptr); state->num_nodes = 0; state->public_key_list = public_key_list; public_key_list[i] = (uint8_t *)malloc(sizeof(uint8_t) * TOX_PUBLIC_KEY_SIZE); ck_assert(public_key_list[i] != nullptr); tox_self_get_dht_id(autotoxes[i].tox, public_key_list[i]); tox_events_callback_dht_get_nodes_response(autotoxes[i].dispatch, getnodes_response_cb); printf("Peer %zu dht closenode count total/announce-capable: %d/%d\n", i, tox_dht_get_num_closelist(autotoxes[i].tox), tox_dht_get_num_closelist_announce_capable(autotoxes[i].tox)); } while (!all_nodes_crawled(autotoxes, NUM_TOXES, public_key_list)) { iterate_all_wait(autotoxes, NUM_TOXES, ITERATION_INTERVAL); } for (size_t i = 0; i < NUM_TOXES; ++i) { State *state = (State *)autotoxes[i].state; free_nodes(state->nodes, state->num_nodes); free(public_key_list[i]); } free(public_key_list); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, NUM_TOXES, test_dht_getnodes, sizeof(State), &options); return 0; } #undef NUM_TOXES c-toxcore-0.2.20/auto_tests/encryptsave_test.c0000644060175106017510000002506014714247532017442 0ustar robin#include #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/crypto_core.h" #include "../toxcore/tox.h" #include "../toxencryptsave/toxencryptsave.h" #include "auto_test_support.h" #include "check_compat.h" static unsigned char test_salt[TOX_PASS_SALT_LENGTH] = {0xB1, 0xC2, 0x09, 0xEE, 0x50, 0x6C, 0xF0, 0x20, 0xC4, 0xD6, 0xEB, 0xC0, 0x44, 0x51, 0x3B, 0x60, 0x4B, 0x39, 0x4A, 0xCF, 0x09, 0x53, 0x4F, 0xEA, 0x08, 0x41, 0xFA, 0xCA, 0x66, 0xD2, 0x68, 0x7F}; static unsigned char known_key[TOX_PASS_KEY_LENGTH] = {0x29, 0x36, 0x1c, 0x9e, 0x65, 0xbb, 0x46, 0x8b, 0xde, 0xa1, 0xac, 0xf, 0xd5, 0x11, 0x81, 0xc8, 0x29, 0x28, 0x17, 0x23, 0xa6, 0xc3, 0x6b, 0x77, 0x2e, 0xd7, 0xd3, 0x10, 0xeb, 0xd2, 0xf7, 0xc8}; static const char *pw = "hunter2"; static unsigned int pwlen = 7; static unsigned char known_key2[CRYPTO_SHARED_KEY_SIZE] = {0x7a, 0xfa, 0x95, 0x45, 0x36, 0x8a, 0xa2, 0x5c, 0x40, 0xfd, 0xc0, 0xe2, 0x35, 0x8, 0x7, 0x88, 0xfa, 0xf9, 0x37, 0x86, 0xeb, 0xff, 0x50, 0x4f, 0x3, 0xe2, 0xf6, 0xd9, 0xef, 0x9, 0x17, 0x1}; // same as above, except standard opslimit instead of extra ops limit for test_known_kdf, and hash pw before kdf for compat /* cause I'm shameless */ static void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) { if (*((uint32_t *)userdata) != 974536) { return; } if (length == 7 && memcmp("Gentoo", data, 7) == 0) { tox_friend_add_norequest(m, public_key, nullptr); } } static void test_known_kdf(void) { unsigned char out[CRYPTO_SHARED_KEY_SIZE]; int16_t res = crypto_pwhash_scryptsalsa208sha256(out, CRYPTO_SHARED_KEY_SIZE, pw, pwlen, test_salt, crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 8, crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE); ck_assert_msg(res != -1, "crypto function failed"); ck_assert_msg(memcmp(out, known_key, CRYPTO_SHARED_KEY_SIZE) == 0, "derived key is wrong"); } static void test_save_friend(void) { Tox *tox1 = tox_new_log(nullptr, nullptr, nullptr); Tox *tox2 = tox_new_log(nullptr, nullptr, nullptr); ck_assert_msg(tox1 || tox2, "Failed to create 2 tox instances"); tox_callback_friend_request(tox2, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); uint32_t test = tox_friend_add(tox1, address, (const uint8_t *)"Gentoo", 7, nullptr); ck_assert_msg(test != UINT32_MAX, "Failed to add friend"); size_t size = tox_get_savedata_size(tox1); uint8_t *data = (uint8_t *)malloc(size); ck_assert(data != nullptr); tox_get_savedata(tox1, data); size_t size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t *enc_data = (uint8_t *)malloc(size2); ck_assert(enc_data != nullptr); Tox_Err_Encryption error1; bool ret = tox_pass_encrypt(data, size, (const uint8_t *)"correcthorsebatterystaple", 25, enc_data, &error1); ck_assert_msg(ret, "failed to encrypted save: %d", error1); ck_assert_msg(tox_is_data_encrypted(enc_data), "magic number missing"); struct Tox_Options *options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, enc_data, size2); Tox_Err_New err2; Tox *tox3 = tox_new_log(options, &err2, nullptr); ck_assert_msg(err2 == TOX_ERR_NEW_LOAD_ENCRYPTED, "wrong error! %d. should fail with %d", err2, TOX_ERR_NEW_LOAD_ENCRYPTED); ck_assert_msg(tox3 == nullptr, "tox_new with error should return NULL"); uint8_t *dec_data = (uint8_t *)malloc(size); ck_assert(dec_data != nullptr); Tox_Err_Decryption err3; ret = tox_pass_decrypt(enc_data, size2, (const uint8_t *)"correcthorsebatterystaple", 25, dec_data, &err3); ck_assert_msg(ret, "failed to decrypt save: %d", err3); tox_options_set_savedata_data(options, dec_data, size); tox3 = tox_new_log(options, &err2, nullptr); ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to load from decrypted data: %d", err2); uint8_t address2[TOX_PUBLIC_KEY_SIZE]; ret = tox_friend_get_public_key(tox3, 0, address2, nullptr); ck_assert_msg(ret, "no friends!"); ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, "addresses don't match!"); size = tox_get_savedata_size(tox3); uint8_t *data2 = (uint8_t *)malloc(size); ck_assert(data2 != nullptr); tox_get_savedata(tox3, data2); Tox_Err_Key_Derivation keyerr; Tox_Pass_Key *key = tox_pass_key_derive((const uint8_t *)"123qweasdzxc", 12, &keyerr); ck_assert_msg(key != nullptr, "pass key allocation failure"); memcpy((uint8_t *)key, test_salt, TOX_PASS_SALT_LENGTH); memcpy((uint8_t *)key + TOX_PASS_SALT_LENGTH, known_key2, TOX_PASS_KEY_LENGTH); size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t *encdata2 = (uint8_t *)malloc(size2); ck_assert(encdata2 != nullptr); ret = tox_pass_key_encrypt(key, data2, size, encdata2, &error1); ck_assert_msg(ret, "failed to key encrypt %d", error1); ck_assert_msg(tox_is_data_encrypted(encdata2), "magic number the second missing"); uint8_t *out1 = (uint8_t *)malloc(size); ck_assert(out1 != nullptr); uint8_t *out2 = (uint8_t *)malloc(size); ck_assert(out2 != nullptr); ret = tox_pass_decrypt(encdata2, size2, (const uint8_t *)pw, pwlen, out1, &err3); ck_assert_msg(ret, "failed to pw decrypt %d", err3); ret = tox_pass_key_decrypt(key, encdata2, size2, out2, &err3); ck_assert_msg(ret, "failed to key decrypt %d", err3); ck_assert_msg(memcmp(out1, out2, size) == 0, "differing output data"); // and now with the code in use (I only bothered with manually to debug this, and it seems a waste // to remove the manual check now that it's there) tox_options_set_savedata_data(options, out1, size); Tox *tox4 = tox_new_log(options, &err2, nullptr); ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to new the third"); uint8_t address5[TOX_PUBLIC_KEY_SIZE]; ret = tox_friend_get_public_key(tox4, 0, address5, nullptr); ck_assert_msg(ret, "no friends! the third"); ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, "addresses don't match! the third"); tox_pass_key_free(key); tox_options_free(options); tox_kill(tox1); tox_kill(tox2); tox_kill(tox3); tox_kill(tox4); free(out2); free(out1); free(encdata2); free(data2); free(dec_data); free(enc_data); free(data); } static void test_keys(void) { Tox_Err_Encryption encerr; Tox_Err_Decryption decerr; Tox_Err_Key_Derivation keyerr; const uint8_t *key_char = (const uint8_t *)"123qweasdzxc"; Tox_Pass_Key *key = tox_pass_key_derive(key_char, 12, &keyerr); ck_assert_msg(key != nullptr, "generic failure 1: %d", keyerr); const uint8_t *string = (const uint8_t *)"No Patrick, mayonnaise is not an instrument."; // 44 uint8_t encrypted[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; bool ret = tox_pass_key_encrypt(key, string, 44, encrypted, &encerr); ck_assert_msg(ret, "generic failure 2: %d", encerr); // Testing how tox handles encryption of large messages. int size_large = 30 * 1024 * 1024; int ciphertext_length2a = size_large + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; int plaintext_length2a = size_large; uint8_t *encrypted2a = (uint8_t *)malloc(ciphertext_length2a); ck_assert(encrypted2a != nullptr); uint8_t *in_plaintext2a = (uint8_t *)malloc(plaintext_length2a); ck_assert(in_plaintext2a != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); random_bytes(rng, in_plaintext2a, plaintext_length2a); ret = tox_pass_encrypt(in_plaintext2a, plaintext_length2a, key_char, 12, encrypted2a, &encerr); ck_assert_msg(ret, "tox_pass_encrypt failure 2a: %d", encerr); // Decryption of same message. uint8_t *out_plaintext2a = (uint8_t *)malloc(plaintext_length2a); ck_assert(out_plaintext2a != nullptr); ret = tox_pass_decrypt(encrypted2a, ciphertext_length2a, key_char, 12, out_plaintext2a, &decerr); ck_assert_msg(ret, "tox_pass_decrypt failure 2a: %d", decerr); ck_assert_msg(memcmp(in_plaintext2a, out_plaintext2a, plaintext_length2a) == 0, "Large message decryption failed"); free(encrypted2a); free(in_plaintext2a); free(out_plaintext2a); uint8_t encrypted2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; ret = tox_pass_encrypt(string, 44, key_char, 12, encrypted2, &encerr); ck_assert_msg(ret, "generic failure 3: %d", encerr); uint8_t out1[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; uint8_t out2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; ret = tox_pass_key_decrypt(key, encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, out1, &decerr); ck_assert_msg(ret, "generic failure 4: %d", decerr); ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 1 failed"); ret = tox_pass_decrypt(encrypted2, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, (const uint8_t *)"123qweasdzxc", 12, out2, &decerr); ck_assert_msg(ret, "generic failure 5: %d", decerr); ck_assert_msg(memcmp(out2, string, 44) == 0, "decryption 2 failed"); ret = tox_pass_decrypt(encrypted2, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, nullptr, 0, out2, &decerr); ck_assert_msg(!ret, "Decrypt succeeded with wrong pass"); ck_assert_msg(decerr != TOX_ERR_DECRYPTION_FAILED, "Bad error code %d", decerr); // test that pass_decrypt can decrypt things from pass_key_encrypt ret = tox_pass_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, (const uint8_t *)"123qweasdzxc", 12, out1, &decerr); ck_assert_msg(ret, "generic failure 6: %d", decerr); ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 3 failed"); uint8_t salt[TOX_PASS_SALT_LENGTH]; Tox_Err_Get_Salt salt_err; ck_assert_msg(tox_get_salt(encrypted, salt, &salt_err), "couldn't get salt"); ck_assert_msg(salt_err == TOX_ERR_GET_SALT_OK, "get_salt returned an error"); Tox_Pass_Key *key2 = tox_pass_key_derive_with_salt((const uint8_t *)"123qweasdzxc", 12, salt, &keyerr); ck_assert_msg(key2 != nullptr, "generic failure 7: %d", keyerr); ck_assert_msg(0 == memcmp(key, key2, TOX_PASS_KEY_LENGTH + TOX_PASS_SALT_LENGTH), "salt comparison failed"); tox_pass_key_free(key2); tox_pass_key_free(key); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_known_kdf(); test_save_friend(); test_keys(); return 0; } c-toxcore-0.2.20/auto_tests/file_saving_test.c0000644060175106017510000000665614714247532017377 0ustar robin/* SPDX-License-Identifier: GPL-3.0-or-later * Copyright © 2016-2018 The TokTok team. * Copyright © 2016 Tox project. */ /* * Small test for checking if obtaining savedata, saving it to disk and using * works correctly. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "auto_test_support.h" #include "check_compat.h" #include "../toxencryptsave/toxencryptsave.h" static const char *pphrase = "bar"; static const char *name = "foo"; static const char *savefile = "./save"; static void save_data_encrypted(void) { struct Tox_Options *options = tox_options_new(nullptr); Tox *t = tox_new_log(options, nullptr, nullptr); tox_options_free(options); tox_self_set_name(t, (const uint8_t *)name, strlen(name), nullptr); FILE *f = fopen(savefile, "wb"); size_t size = tox_get_savedata_size(t); uint8_t *clear = (uint8_t *)malloc(size); /*this function does not write any data at all*/ tox_get_savedata(t, clear); size += TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t *cipher = (uint8_t *)malloc(size); Tox_Err_Encryption eerr; ck_assert_msg(tox_pass_encrypt(clear, size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH, (const uint8_t *)pphrase, strlen(pphrase), cipher, &eerr), "Could not encrypt, error code %d.", eerr); size_t written_value = fwrite(cipher, sizeof(*cipher), size, f); printf("written written_value = %u of %u\n", (unsigned)written_value, (unsigned)size); free(cipher); free(clear); fclose(f); tox_kill(t); } static void load_data_decrypted(void) { FILE *f = fopen(savefile, "rb"); ck_assert(f != nullptr); fseek(f, 0, SEEK_END); int64_t size = ftell(f); fseek(f, 0, SEEK_SET); ck_assert_msg(0 <= size && size <= UINT_MAX, "file size out of range"); uint8_t *cipher = (uint8_t *)malloc(size); ck_assert(cipher != nullptr); uint8_t *clear = (uint8_t *)malloc(size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH); ck_assert(clear != nullptr); size_t read_value = fread(cipher, sizeof(*cipher), size, f); printf("Read read_value = %u of %u\n", (unsigned)read_value, (unsigned)size); Tox_Err_Decryption derr; ck_assert_msg(tox_pass_decrypt(cipher, size, (const uint8_t *)pphrase, strlen(pphrase), clear, &derr), "Could not decrypt, error code %d.", derr); struct Tox_Options *options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, clear, size); Tox_Err_New err; Tox *t = tox_new_log(options, &err, nullptr); tox_options_free(options); ck_assert_msg(t != nullptr, "tox_new returned the error value %d", err); uint8_t *readname = (uint8_t *)malloc(tox_self_get_name_size(t)); ck_assert(readname != nullptr); tox_self_get_name(t, readname); ck_assert_msg(memcmp(readname, name, tox_self_get_name_size(t)) == 0, "name returned by tox_self_get_name does not match expected result"); tox_kill(t); free(clear); free(cipher); free(readname); fclose(f); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); save_data_encrypted(); load_data_decrypted(); ck_assert_msg(remove(savefile) == 0, "Could not remove the savefile."); return 0; } c-toxcore-0.2.20/auto_tests/file_streaming_test.c0000644060175106017510000002274214714247532020073 0ustar robin/* File transfer test: streaming version (no known size). */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif #ifdef TOX_LOCALHOST #undef TOX_LOCALHOST #endif #if USE_IPV6 #define TOX_LOCALHOST "::1" #else #define TOX_LOCALHOST "127.0.0.1" #endif static void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) { if (length == 7 && memcmp("Gentoo", data, 7) == 0) { tox_friend_add_norequest(m, public_key, nullptr); } } static uint64_t size_recv; static uint64_t sending_pos; static uint8_t file_cmp_id[TOX_FILE_ID_LENGTH]; static uint32_t file_accepted; static uint64_t file_size; static void tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t filesize, const uint8_t *filename, size_t filename_length, void *userdata) { ck_assert_msg(kind == TOX_FILE_KIND_DATA, "bad kind"); ck_assert_msg(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0, "bad filename"); uint8_t file_id[TOX_FILE_ID_LENGTH]; ck_assert_msg(tox_file_get_file_id(tox, friend_number, file_number, file_id, nullptr), "tox_file_get_file_id error"); ck_assert_msg(memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) == 0, "bad file_id"); const uint8_t empty[TOX_FILE_ID_LENGTH] = {0}; ck_assert_msg(memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) != 0, "empty file_id"); file_size = filesize; if (filesize) { sending_pos = size_recv = 1337; Tox_Err_File_Seek err_s; ck_assert_msg(tox_file_seek(tox, friend_number, file_number, 1337, &err_s), "tox_file_seek error"); ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, "tox_file_seek wrong error"); } else { sending_pos = size_recv = 0; } Tox_Err_File_Control error; ck_assert_msg(tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error), "tox_file_control failed. %i", error); ++file_accepted; Tox_Err_File_Seek err_s; ck_assert_msg(!tox_file_seek(tox, friend_number, file_number, 1234, &err_s), "tox_file_seek no error"); ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, "tox_file_seek wrong error"); } static uint32_t sendf_ok; static void file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, Tox_File_Control control, void *userdata) { /* First send file num is 0.*/ if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME) { sendf_ok = 1; } } static uint64_t max_sending; static bool m_send_reached; static uint8_t sending_num; static bool file_sending_done; static void tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length, void *user_data) { ck_assert_msg(sendf_ok, "didn't get resume control"); ck_assert_msg(sending_pos == position, "bad position %lu", (unsigned long)position); if (length == 0) { ck_assert_msg(!file_sending_done, "file sending already done"); file_sending_done = 1; return; } if (position + length > max_sending) { ck_assert_msg(!m_send_reached, "requested done file transfer"); length = max_sending - position; m_send_reached = 1; } VLA(uint8_t, f_data, length); memset(f_data, sending_num, length); Tox_Err_File_Send_Chunk error; tox_file_send_chunk(tox, friend_number, file_number, position, f_data, length, &error); ck_assert_msg(error == TOX_ERR_FILE_SEND_CHUNK_OK, "could not send chunk, error num=%d pos=%d len=%d", (int)error, (int)position, (int)length); ++sending_num; sending_pos += length; } static uint8_t num; static bool file_recv; static void write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, size_t length, void *user_data) { ck_assert_msg(size_recv == position, "bad position"); if (length == 0) { file_recv = 1; return; } VLA(uint8_t, f_data, length); memset(f_data, num, length); ++num; ck_assert_msg(memcmp(f_data, data, length) == 0, "FILE_CORRUPTED"); size_recv += length; } static void file_transfer_test(void) { printf("Starting test: few_clients\n"); uint32_t index[] = { 1, 2, 3 }; long long unsigned int cur_time = time(nullptr); Tox_Err_New t_n_error; Tox *tox1 = tox_new_log(nullptr, &t_n_error, &index[0]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); Tox *tox2 = tox_new_log(nullptr, &t_n_error, &index[1]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); Tox *tox3 = tox_new_log(nullptr, &t_n_error, &index[2]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); ck_assert_msg(tox1 && tox2 && tox3, "Failed to create 3 tox instances"); tox_callback_friend_request(tox2, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); uint32_t test = tox_friend_add(tox3, address, (const uint8_t *)"Gentoo", 7, nullptr); ck_assert_msg(test == 0, "Failed to add friend error code: %u", test); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, TOX_LOCALHOST, dht_port, dht_key, nullptr); tox_bootstrap(tox3, TOX_LOCALHOST, dht_port, dht_key, nullptr); printf("Waiting for toxes to come online\n"); do { tox_iterate(tox1, nullptr); tox_iterate(tox2, nullptr); tox_iterate(tox3, nullptr); printf("Connections: self (%d, %d, %d), friends (%d, %d)\n", tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2), tox_self_get_connection_status(tox3), tox_friend_get_connection_status(tox2, 0, nullptr), tox_friend_get_connection_status(tox3, 0, nullptr)); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox3) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(tox2, 0, nullptr) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(tox3, 0, nullptr) == TOX_CONNECTION_NONE); printf("Starting file transfer test: 100MiB file.\n"); file_accepted = file_size = sendf_ok = size_recv = 0; file_recv = 0; max_sending = UINT64_MAX; printf("Starting file streaming transfer test.\n"); file_sending_done = 0; file_accepted = 0; file_size = 0; sendf_ok = 0; size_recv = 0; file_recv = 0; tox_callback_file_recv_chunk(tox3, write_file); tox_callback_file_recv_control(tox2, file_print_control); tox_callback_file_chunk_request(tox2, tox_file_chunk_request); tox_callback_file_recv_control(tox3, file_print_control); tox_callback_file_recv(tox3, tox_file_receive); const uint64_t totalf_size = UINT64_MAX; Tox_File_Number fnum = tox_file_send( tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); Tox_Err_File_Get gfierr; ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); max_sending = 100 * 1024; m_send_reached = 0; do { tox_iterate(tox1, nullptr); tox_iterate(tox2, nullptr); tox_iterate(tox3, nullptr); uint32_t tox1_interval = tox_iteration_interval(tox1); uint32_t tox2_interval = tox_iteration_interval(tox2); uint32_t tox3_interval = tox_iteration_interval(tox3); c_sleep(min_u32(tox1_interval, min_u32(tox2_interval, tox3_interval))); } while (!file_sending_done); ck_assert_msg(sendf_ok && file_recv && m_send_reached && totalf_size == file_size && size_recv == max_sending && sending_pos == size_recv && file_accepted == 1, "something went wrong in file transfer %u %u %u %u %u %u %u %lu %lu %lu %lu", sendf_ok, file_recv, m_send_reached, totalf_size == file_size, size_recv == max_sending, sending_pos == size_recv, file_accepted == 1, (unsigned long)totalf_size, (unsigned long)file_size, (unsigned long)size_recv, (unsigned long)sending_pos); printf("file_transfer_test succeeded, took %llu seconds\n", time(nullptr) - cur_time); tox_kill(tox1); tox_kill(tox2); tox_kill(tox3); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); file_transfer_test(); return 0; } c-toxcore-0.2.20/auto_tests/file_transfer_test.c0000644060175106017510000003474314714247532017732 0ustar robin/* File transfer test. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif #ifdef TOX_LOCALHOST #undef TOX_LOCALHOST #endif #if USE_IPV6 #define TOX_LOCALHOST "::1" #else #define TOX_LOCALHOST "127.0.0.1" #endif static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { Tox *tox = (Tox *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *data = tox_event_friend_request_get_message(event); const size_t length = tox_event_friend_request_get_message_length(event); if (length == 7 && memcmp("Gentoo", data, 7) == 0) { tox_friend_add_norequest(tox, public_key, nullptr); } } static uint64_t size_recv; static uint64_t sending_pos; static uint8_t file_cmp_id[TOX_FILE_ID_LENGTH]; static uint32_t file_accepted; static uint64_t file_size; static void tox_file_receive(const Tox_Event_File_Recv *event, void *userdata) { Tox *state_tox = (Tox *)userdata; const uint32_t friend_number = tox_event_file_recv_get_friend_number(event); const uint32_t file_number = tox_event_file_recv_get_file_number(event); const uint32_t kind = tox_event_file_recv_get_kind(event); const uint64_t filesize = tox_event_file_recv_get_file_size(event); const uint8_t *filename = tox_event_file_recv_get_filename(event); const size_t filename_length = tox_event_file_recv_get_filename_length(event); ck_assert_msg(kind == TOX_FILE_KIND_DATA, "bad kind"); ck_assert_msg(filename_length == sizeof("Gentoo.exe") && memcmp(filename, "Gentoo.exe", sizeof("Gentoo.exe")) == 0, "bad filename"); uint8_t file_id[TOX_FILE_ID_LENGTH]; ck_assert_msg(tox_file_get_file_id(state_tox, friend_number, file_number, file_id, nullptr), "tox_file_get_file_id error"); ck_assert_msg(memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) == 0, "bad file_id"); const uint8_t empty[TOX_FILE_ID_LENGTH] = {0}; ck_assert_msg(memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) != 0, "empty file_id"); file_size = filesize; if (filesize) { sending_pos = size_recv = 1337; Tox_Err_File_Seek err_s; ck_assert_msg(tox_file_seek(state_tox, friend_number, file_number, 1337, &err_s), "tox_file_seek error"); ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, "tox_file_seek wrong error"); } else { sending_pos = size_recv = 0; } Tox_Err_File_Control error; ck_assert_msg(tox_file_control(state_tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error), "tox_file_control failed. %i", error); ++file_accepted; Tox_Err_File_Seek err_s; ck_assert_msg(!tox_file_seek(state_tox, friend_number, file_number, 1234, &err_s), "tox_file_seek no error"); ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, "tox_file_seek wrong error"); } static uint32_t sendf_ok; static void file_print_control(const Tox_Event_File_Recv_Control *event, void *userdata) { const uint32_t file_number = tox_event_file_recv_control_get_file_number(event); const Tox_File_Control control = tox_event_file_recv_control_get_control(event); /* First send file num is 0.*/ if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME) { sendf_ok = 1; } } static uint64_t max_sending; static bool m_send_reached; static uint8_t sending_num; static bool file_sending_done; static void tox_file_chunk_request(const Tox_Event_File_Chunk_Request *event, void *user_data) { Tox *state_tox = (Tox *)user_data; const uint32_t friend_number = tox_event_file_chunk_request_get_friend_number(event); const uint32_t file_number = tox_event_file_chunk_request_get_file_number(event); const uint64_t position = tox_event_file_chunk_request_get_position(event); size_t length = tox_event_file_chunk_request_get_length(event); ck_assert_msg(sendf_ok, "didn't get resume control"); ck_assert_msg(sending_pos == position, "bad position %lu (should be %lu)", (unsigned long)position, (unsigned long)sending_pos); if (length == 0) { ck_assert_msg(!file_sending_done, "file sending already done"); file_sending_done = 1; return; } if (position + length > max_sending) { ck_assert_msg(!m_send_reached, "requested done file transfer"); length = max_sending - position; m_send_reached = 1; } VLA(uint8_t, f_data, length); memset(f_data, sending_num, length); Tox_Err_File_Send_Chunk error; tox_file_send_chunk(state_tox, friend_number, file_number, position, f_data, length, &error); ck_assert_msg(error == TOX_ERR_FILE_SEND_CHUNK_OK, "could not send chunk, error num=%d pos=%d len=%d", (int)error, (int)position, (int)length); ++sending_num; sending_pos += length; } static uint8_t num; static bool file_recv; static void write_file(const Tox_Event_File_Recv_Chunk *event, void *user_data) { const uint64_t position = tox_event_file_recv_chunk_get_position(event); const uint8_t *data = tox_event_file_recv_chunk_get_data(event); const size_t length = tox_event_file_recv_chunk_get_data_length(event); ck_assert_msg(size_recv == position, "bad position"); if (length == 0) { file_recv = 1; return; } VLA(uint8_t, f_data, length); memset(f_data, num, length); ++num; ck_assert_msg(memcmp(f_data, data, length) == 0, "FILE_CORRUPTED"); size_recv += length; } static void iterate_and_dispatch(const Tox_Dispatch *dispatch, Tox *tox) { Tox_Err_Events_Iterate err; Tox_Events *events; events = tox_events_iterate(tox, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch, events, tox); tox_events_free(events); } static void file_transfer_test(void) { printf("Starting test: few_clients\n"); uint32_t index[] = { 1, 2, 3 }; long long unsigned int cur_time = time(nullptr); Tox_Err_New t_n_error; Tox *tox1 = tox_new_log(nullptr, &t_n_error, &index[0]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); Tox *tox2 = tox_new_log(nullptr, &t_n_error, &index[1]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); Tox *tox3 = tox_new_log(nullptr, &t_n_error, &index[2]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "wrong error"); ck_assert_msg(tox1 && tox2 && tox3, "Failed to create 3 tox instances"); tox_events_init(tox1); tox_events_init(tox2); tox_events_init(tox3); Tox_Dispatch *dispatch1 = tox_dispatch_new(nullptr); ck_assert(dispatch1 != nullptr); Tox_Dispatch *dispatch2 = tox_dispatch_new(nullptr); ck_assert(dispatch2 != nullptr); Tox_Dispatch *dispatch3 = tox_dispatch_new(nullptr); ck_assert(dispatch3 != nullptr); tox_events_callback_friend_request(dispatch2, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); uint32_t test = tox_friend_add(tox3, address, (const uint8_t *)"Gentoo", 7, nullptr); ck_assert_msg(test == 0, "Failed to add friend error code: %u", test); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, TOX_LOCALHOST, dht_port, dht_key, nullptr); tox_bootstrap(tox3, TOX_LOCALHOST, dht_port, dht_key, nullptr); printf("Waiting for toxes to come online\n"); do { iterate_and_dispatch(dispatch1, tox1); iterate_and_dispatch(dispatch2, tox2); iterate_and_dispatch(dispatch3, tox3); printf("Connections: self (%d, %d, %d), friends (%d, %d)\n", tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2), tox_self_get_connection_status(tox3), tox_friend_get_connection_status(tox2, 0, nullptr), tox_friend_get_connection_status(tox3, 0, nullptr)); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox3) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(tox2, 0, nullptr) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(tox3, 0, nullptr) == TOX_CONNECTION_NONE); printf("Starting file transfer test: 100MiB file.\n"); file_accepted = file_size = sendf_ok = size_recv = 0; file_recv = 0; max_sending = UINT64_MAX; uint64_t f_time = time(nullptr); tox_events_callback_file_recv_chunk(dispatch3, write_file); tox_events_callback_file_recv_control(dispatch2, file_print_control); tox_events_callback_file_chunk_request(dispatch2, tox_file_chunk_request); tox_events_callback_file_recv_control(dispatch3, file_print_control); tox_events_callback_file_recv(dispatch3, tox_file_receive); uint64_t totalf_size = 100 * 1024 * 1024; uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); Tox_Err_File_Get gfierr; ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); const size_t max_iterations = INT16_MAX; for (size_t i = 0; i < max_iterations; i++) { iterate_and_dispatch(dispatch1, tox1); iterate_and_dispatch(dispatch2, tox2); iterate_and_dispatch(dispatch3, tox3); if (file_sending_done) { ck_assert_msg(sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv && file_accepted == 1, "Something went wrong in file transfer %u %u %u %u %u %u %lu %lu %lu", sendf_ok, file_recv, totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, (unsigned long)totalf_size, (unsigned long)size_recv, (unsigned long)sending_pos); break; } uint32_t tox1_interval = tox_iteration_interval(tox1); uint32_t tox2_interval = tox_iteration_interval(tox2); uint32_t tox3_interval = tox_iteration_interval(tox3); if ((i + 1) % 500 == 0) { printf("after %u iterations: %.2fMiB done\n", (unsigned int)i + 1, (double)size_recv / 1024 / 1024); } c_sleep(min_u32(tox1_interval, min_u32(tox2_interval, tox3_interval))); } ck_assert_msg(file_sending_done, "file sending did not complete after %u iterations: sendf_ok:%u file_recv:%u " "totalf_size==file_size:%u size_recv==file_size:%u sending_pos==size_recv:%u file_accepted:%u " "totalf_size:%lu size_recv:%lu sending_pos:%lu", (unsigned int)max_iterations, sendf_ok, file_recv, totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, (unsigned long)totalf_size, (unsigned long)size_recv, (unsigned long)sending_pos); printf("100MiB file sent in %lu seconds\n", (unsigned long)(time(nullptr) - f_time)); printf("starting file 0 transfer test.\n"); file_sending_done = 0; file_accepted = 0; file_size = 0; sendf_ok = 0; size_recv = 0; file_recv = 0; tox_events_callback_file_recv_chunk(dispatch3, write_file); tox_events_callback_file_recv_control(dispatch2, file_print_control); tox_events_callback_file_chunk_request(dispatch2, tox_file_chunk_request); tox_events_callback_file_recv_control(dispatch3, file_print_control); tox_events_callback_file_recv(dispatch3, tox_file_receive); totalf_size = 0; fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, nullptr, (const uint8_t *)"Gentoo.exe", sizeof("Gentoo.exe"), nullptr); ck_assert_msg(fnum != UINT32_MAX, "tox_new_file_sender fail"); ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, "wrong error"); ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), "tox_file_get_file_id didn't fail"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, "wrong error"); ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), "tox_file_get_file_id failed"); ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, "wrong error"); do { uint32_t tox1_interval = tox_iteration_interval(tox1); uint32_t tox2_interval = tox_iteration_interval(tox2); uint32_t tox3_interval = tox_iteration_interval(tox3); c_sleep(min_u32(tox1_interval, min_u32(tox2_interval, tox3_interval))); iterate_and_dispatch(dispatch1, tox1); iterate_and_dispatch(dispatch2, tox2); iterate_and_dispatch(dispatch3, tox3); } while (!file_sending_done); ck_assert_msg(sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv && file_accepted == 1, "something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu", sendf_ok, file_recv, totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, (unsigned long long)totalf_size, (unsigned long long)size_recv, (unsigned long long)sending_pos); printf("file_transfer_test succeeded, took %llu seconds\n", time(nullptr) - cur_time); tox_dispatch_free(dispatch3); tox_dispatch_free(dispatch2); tox_dispatch_free(dispatch1); tox_kill(tox3); tox_kill(tox2); tox_kill(tox1); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); file_transfer_test(); return 0; } c-toxcore-0.2.20/auto_tests/forwarding_test.c0000644060175106017510000002604114714247532017241 0ustar robin#include #include #include #include "../toxcore/tox.h" #include "../toxcore/announce.h" #include "../testing/misc_tools.h" #include "../toxcore/mono_time.h" #include "../toxcore/forwarding.h" #include "../toxcore/net_crypto.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif static inline IP get_loopback(void) { IP ip; #if USE_IPV6 ip.family = net_family_ipv6(); ip.ip.v6 = get_ip6_loopback(); #else ip.family = net_family_ipv4(); ip.ip.v4 = get_ip4_loopback(); #endif return ip; } #define NUM_FORWARDER 20 #define NUM_FORWARDER_TCP 5 #define NUM_FORWARDER_DHT (NUM_FORWARDER - NUM_FORWARDER_TCP) #define NUM_FORWARDING_ITERATIONS 1 #define FORWARD_SEND_INTERVAL 2 #define FORWARDING_BASE_PORT 36571 typedef struct Test_Data { Networking_Core *net; uint32_t send_back; uint64_t sent; bool returned; } Test_Data; static void test_forwarded_request_cb(void *object, const IP_Port *forwarder, const uint8_t *sendback, uint16_t sendback_length, const uint8_t *data, uint16_t length, void *userdata) { const Test_Data *test_data = (const Test_Data *)object; const uint8_t *index = (const uint8_t *)userdata; if (length != 12 || memcmp("hello: ", data, 8) != 0) { printf("[%u] got unexpected data of length %d\n", *index, length); return; } uint8_t reply[12]; memcpy(reply, "reply: ", 8); memcpy(reply + 8, data + 8, 4); ck_assert_msg(forward_reply(test_data->net, forwarder, sendback, sendback_length, reply, 12), "[%u] forward_reply failed", *index); } static void test_forwarded_response_cb(void *object, const uint8_t *data, uint16_t length, void *userdata) { Test_Data *test_data = (Test_Data *)object; const uint8_t *index = (const uint8_t *)userdata; if (length != 12 || memcmp("reply: ", data, 8) != 0) { printf("[%u] got unexpected data of length %d\n", *index, length); return; } uint32_t send_back; net_unpack_u32(data + 8, &send_back); if (test_data->send_back == send_back) { test_data->returned = true; } } static bool all_returned(Test_Data *test_data) { for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { if (!test_data[i].returned) { return false; } } return true; } typedef struct Forwarding_Subtox { Logger *log; Mono_Time *mono_time; Networking_Core *net; DHT *dht; Net_Crypto *c; Forwarding *forwarding; Announcements *announce; } Forwarding_Subtox; static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp, uint32_t *index, uint16_t port) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); Forwarding_Subtox *subtox = (Forwarding_Subtox *)calloc(1, sizeof(Forwarding_Subtox)); ck_assert(subtox != nullptr); subtox->log = logger_new(); ck_assert(subtox->log != nullptr); logger_callback_log(subtox->log, print_debug_logger, nullptr, index); subtox->mono_time = mono_time_new(mem, nullptr, nullptr); if (no_udp) { subtox->net = new_networking_no_udp(subtox->log, mem, ns); } else { const IP ip = get_loopback(); subtox->net = new_networking_ex(subtox->log, mem, ns, &ip, port, port, nullptr); } subtox->dht = new_dht(subtox->log, mem, rng, ns, subtox->mono_time, subtox->net, true, true); const TCP_Proxy_Info inf = {{{{0}}}}; subtox->c = new_net_crypto(subtox->log, mem, rng, ns, subtox->mono_time, subtox->dht, &inf); subtox->forwarding = new_forwarding(subtox->log, rng, subtox->mono_time, subtox->dht); ck_assert(subtox->forwarding != nullptr); subtox->announce = new_announcements(subtox->log, mem, rng, subtox->mono_time, subtox->forwarding); ck_assert(subtox->announce != nullptr); return subtox; } static void kill_forwarding_subtox(const Memory *mem, Forwarding_Subtox *subtox) { kill_announcements(subtox->announce); kill_forwarding(subtox->forwarding); kill_net_crypto(subtox->c); kill_dht(subtox->dht); kill_networking(subtox->net); mono_time_free(mem, subtox->mono_time); logger_kill(subtox->log); free(subtox); } static void test_forwarding(void) { const Memory *mem = os_memory(); ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); uint32_t index[NUM_FORWARDER]; Forwarding_Subtox *subtoxes[NUM_FORWARDER]; Test_Data test_data[NUM_FORWARDER]; const IP ip = get_loopback(); for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { index[i] = i + 1; subtoxes[i] = new_forwarding_subtox(mem, i < NUM_FORWARDER_TCP, &index[i], FORWARDING_BASE_PORT + i); test_data[i].net = subtoxes[i]->net; test_data[i].send_back = 0; test_data[i].sent = 0; test_data[i].returned = false; set_callback_forwarded_request(subtoxes[i]->forwarding, test_forwarded_request_cb, &test_data[i]); set_callback_forwarded_response(subtoxes[i]->forwarding, test_forwarded_response_cb, &test_data[i]); set_forwarding_packet_tcp_connection_callback(nc_get_tcp_c(subtoxes[i]->c), test_forwarded_response_cb, &test_data[i]); } printf("testing forwarding via tcp relays and dht\n"); struct Tox_Options *opts = tox_options_new(nullptr); uint16_t forwarder_tcp_relay_port = 36570; Tox *relay = nullptr; // Try a few different ports. for (uint8_t i = 0; i < 100; ++i) { tox_options_set_tcp_port(opts, forwarder_tcp_relay_port); relay = tox_new_log(opts, nullptr, nullptr); if (relay != nullptr) { break; } ++forwarder_tcp_relay_port; } tox_options_free(opts); ck_assert_msg(relay != nullptr, "Failed to create TCP relay"); IP_Port relay_ipport_tcp = {ip, net_htons(forwarder_tcp_relay_port)}; uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(relay, dpk); printf("1-%d connected only to TCP server; %d-%d connected only to DHT\n", NUM_FORWARDER_TCP, NUM_FORWARDER_TCP + 1, NUM_FORWARDER); for (uint32_t i = 0; i < NUM_FORWARDER_TCP; ++i) { set_tcp_onion_status(nc_get_tcp_c(subtoxes[i]->c), 1); ck_assert_msg(add_tcp_relay(subtoxes[i]->c, &relay_ipport_tcp, dpk) == 0, "Failed to add TCP relay"); } IP_Port relay_ipport_udp = {ip, net_htons(tox_self_get_udp_port(relay, nullptr))}; for (uint32_t i = NUM_FORWARDER_TCP; i < NUM_FORWARDER; ++i) { dht_bootstrap(subtoxes[i]->dht, &relay_ipport_udp, dpk); } printf("allowing DHT to populate\n"); uint16_t dht_establish_iterations = NUM_FORWARDER * 5; for (uint32_t n = 0; n < NUM_FORWARDING_ITERATIONS; ++n) { for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { test_data[i].sent = 0; test_data[i].returned = false; } do { for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { Forwarding_Subtox *const subtox = subtoxes[i]; mono_time_update(subtox->mono_time); networking_poll(subtox->net, &index[i]); do_net_crypto(subtox->c, &index[i]); do_dht(subtox->dht); if (dht_establish_iterations || test_data[i].returned || !mono_time_is_timeout(subtox->mono_time, test_data[i].sent, FORWARD_SEND_INTERVAL)) { continue; } printf("%u", i + 1); if (i < NUM_FORWARDER_TCP) { printf(" --> TCPRelay"); } const uint16_t chain_length = i < NUM_FORWARDER_TCP ? i % 5 : i % 4 + 1; uint8_t chain_keys[4 * CRYPTO_PUBLIC_KEY_SIZE]; uint32_t chain_i = NUM_FORWARDER_TCP + (random_u32(rng) % NUM_FORWARDER_DHT); const IP_Port first_ipp = {ip, net_htons(FORWARDING_BASE_PORT + chain_i)}; printf(" --> %u", chain_i + 1); for (uint16_t j = 0; j < chain_length; ++j) { // pick random different dht node: chain_i += 1 + random_u32(rng) % (NUM_FORWARDER_DHT - 1); chain_i = NUM_FORWARDER_TCP + (chain_i - NUM_FORWARDER_TCP) % NUM_FORWARDER_DHT; const uint8_t *dest_pubkey = dht_get_self_public_key(subtoxes[chain_i]->dht); memcpy(chain_keys + j * CRYPTO_PUBLIC_KEY_SIZE, dest_pubkey, CRYPTO_PUBLIC_KEY_SIZE); printf(" --> %u", chain_i + 1); } printf("\n"); const uint16_t length = 12; uint8_t data[12]; memcpy(data, "hello: ", 8); test_data[i].send_back = random_u32(rng); net_pack_u32(data + 8, test_data[i].send_back); if (i < NUM_FORWARDER_TCP) { IP_Port tcp_forwarder; if (!get_random_tcp_conn_ip_port(subtox->c, &tcp_forwarder)) { continue; } if (send_tcp_forward_request(subtox->log, subtox->c, &tcp_forwarder, &first_ipp, chain_keys, chain_length, data, length) == 0) { test_data[i].sent = mono_time_get(subtox->mono_time); } } else { if (send_forward_request(subtox->net, &first_ipp, chain_keys, chain_length, data, length)) { test_data[i].sent = mono_time_get(subtox->mono_time); } } } tox_iterate(relay, nullptr); if (dht_establish_iterations) { --dht_establish_iterations; if (!dht_establish_iterations) { printf("making forward requests and expecting replies\n"); } } c_sleep(50); } while (!all_returned(test_data)); // This doesn't really belong in this test. // It can be removed once the full announce client test is in place. printf("checking that nodes are marked as announce nodes\n"); Node_format nodes[MAX_SENT_NODES]; ck_assert(NUM_FORWARDER - NUM_FORWARDER_TCP > 1); for (uint32_t i = NUM_FORWARDER_TCP; i < NUM_FORWARDER; ++i) { ck_assert_msg(get_close_nodes(subtoxes[i]->dht, dht_get_self_public_key(subtoxes[i]->dht), nodes, net_family_unspec(), true, true) > 0, "node %u has no nodes marked as announce nodes", i); } } for (uint32_t i = 0; i < NUM_FORWARDER; ++i) { kill_forwarding_subtox(mem, subtoxes[i]); } tox_kill(relay); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_forwarding(); return 0; } c-toxcore-0.2.20/auto_tests/friend_connection_test.c0000644060175106017510000000120514714247532020560 0ustar robin/* Tests that we can make a friend connection. * * This is the simplest test that brings up two toxes that can talk to each * other. It's useful as a copy/pasteable starting point for testing other * features. */ #include #include "auto_test_support.h" static void friend_connection_test(AutoTox *toxes) { // Nothing to do here. When copying this test, add test-specific code here. } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, friend_connection_test, 0, &options); return 0; } c-toxcore-0.2.20/auto_tests/friend_request_spam_test.c0000644060175106017510000000502714714247532021137 0ustar robin/* Tests what happens when spamming friend requests from lots of temporary toxes. */ #include #include #include #include #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "../testing/misc_tools.h" #include "auto_test_support.h" #include "check_compat.h" #define FR_MESSAGE "Gentoo" // TODO(iphydf): Investigate friend request spam: receiving more than 32 at a time means any further // friend requests are dropped on the floor and aren't seen again. #define FR_TOX_COUNT 33 typedef struct State { bool unused; } State; static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { AutoTox *autotox = (AutoTox *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *data = tox_event_friend_request_get_message(event); const size_t length = tox_event_friend_request_get_message_length(event); ck_assert_msg(length == sizeof(FR_MESSAGE) && memcmp(FR_MESSAGE, data, sizeof(FR_MESSAGE)) == 0, "unexpected friend request message"); tox_friend_add_norequest(autotox->tox, public_key, nullptr); } static void test_friend_request(AutoTox *autotoxes) { const time_t con_time = time(nullptr); printf("All toxes add tox1 as friend.\n"); tox_events_callback_friend_request(autotoxes[0].dispatch, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(autotoxes[0].tox, address); for (uint32_t i = 2; i < FR_TOX_COUNT; ++i) { Tox_Err_Friend_Add err; tox_friend_add(autotoxes[i].tox, address, (const uint8_t *)FR_MESSAGE, sizeof(FR_MESSAGE), &err); ck_assert_msg(err == TOX_ERR_FRIEND_ADD_OK, "tox %u failed to add friend error code: %d", autotoxes[i].index, err); } for (uint32_t t = 0; t < 100; ++t) { if (all_friends_connected(autotoxes, FR_TOX_COUNT)) { break; } iterate_all_wait(autotoxes, FR_TOX_COUNT, ITERATION_INTERVAL); } const size_t size = tox_self_get_friend_list_size(autotoxes[0].tox); printf("Tox clients connected took %lu seconds; tox1 has %u friends.\n", (unsigned long)(time(nullptr) - con_time), (unsigned int)size); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, FR_TOX_COUNT, test_friend_request, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/friend_request_test.c0000644060175106017510000000703214714247532020115 0ustar robin/* Tests that we can add friends. */ #include #include #include #include #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "../testing/misc_tools.h" #include "auto_test_support.h" #include "check_compat.h" #define FR_MESSAGE "Gentoo" static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { Tox *state_tox = (Tox *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *data = tox_event_friend_request_get_message(event); const size_t length = tox_event_friend_request_get_message_length(event); ck_assert_msg(length == sizeof(FR_MESSAGE) && memcmp(FR_MESSAGE, data, sizeof(FR_MESSAGE)) == 0, "unexpected friend request message"); tox_friend_add_norequest(state_tox, public_key, nullptr); } static void iterate2_wait(const Tox_Dispatch *dispatch, Tox *tox1, Tox *tox2) { Tox_Err_Events_Iterate err; Tox_Events *events; events = tox_events_iterate(tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch, events, tox1); tox_events_free(events); events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch, events, tox2); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } static void test_friend_request(void) { printf("Initialising 2 toxes.\n"); uint32_t index[] = { 1, 2 }; const time_t cur_time = time(nullptr); Tox *const tox1 = tox_new_log(nullptr, nullptr, &index[0]); Tox *const tox2 = tox_new_log(nullptr, nullptr, &index[1]); ck_assert_msg(tox1 && tox2, "failed to create 2 tox instances"); tox_events_init(tox1); tox_events_init(tox2); printf("Bootstrapping tox2 off tox1.\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr); Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); do { iterate2_wait(dispatch, tox1, tox2); } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE); printf("Toxes are online, took %lu seconds.\n", (unsigned long)(time(nullptr) - cur_time)); const time_t con_time = time(nullptr); printf("Tox1 adds tox2 as friend, tox2 accepts.\n"); tox_events_callback_friend_request(dispatch, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); const uint32_t test = tox_friend_add(tox1, address, (const uint8_t *)FR_MESSAGE, sizeof(FR_MESSAGE), nullptr); ck_assert_msg(test == 0, "failed to add friend error code: %u", test); do { iterate2_wait(dispatch, tox1, tox2); } while (tox_friend_get_connection_status(tox1, 0, nullptr) != TOX_CONNECTION_UDP || tox_friend_get_connection_status(tox2, 0, nullptr) != TOX_CONNECTION_UDP); printf("Tox clients connected took %lu seconds.\n", (unsigned long)(time(nullptr) - con_time)); printf("friend_request_test succeeded, took %lu seconds.\n", (unsigned long)(time(nullptr) - cur_time)); tox_dispatch_free(dispatch); tox_kill(tox1); tox_kill(tox2); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_friend_request(); return 0; } c-toxcore-0.2.20/auto_tests/group_general_test.c0000644060175106017510000004366414714247532017742 0ustar robin/* * Tests that we can connect to a public group chat through the DHT and make basic queries * about the group, other peers, and ourselves. We also make sure we can disconnect and * reconnect to a group while retaining our credentials. */ #include #include #include #include "auto_test_support.h" #include "../toxcore/tox_private.h" typedef struct State { size_t peer_joined_count; size_t self_joined_count; size_t peer_exit_count; bool peer_nick; bool peer_status; uint32_t peer_id; bool is_founder; } State; #define NUM_GROUP_TOXES 2 #define GROUP_NAME "NASA Headquarters" #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) #define TOPIC "Funny topic here" #define TOPIC_LEN (sizeof(TOPIC) - 1) #define PEER0_NICK "Lois" #define PEER0_NICK_LEN (sizeof(PEER0_NICK) - 1) #define PEER0_NICK2 "Terry Davis" #define PEER0_NICK2_LEN (sizeof(PEER0_NICK2) - 1) #define PEER1_NICK "Bran" #define PEER1_NICK_LEN (sizeof(PEER1_NICK) - 1) #define EXIT_MESSAGE "Goodbye world" #define EXIT_MESSAGE_LEN (sizeof(EXIT_MESSAGE) - 1) #define PEER_LIMIT 20 static void print_ip(const Tox *tox, uint32_t groupnumber, uint32_t peer_id) { Tox_Err_Group_Peer_Query err; size_t length = tox_group_peer_get_ip_address_size(tox, groupnumber, peer_id, &err); ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address size: error %d", err); uint8_t ip_str[TOX_GROUP_PEER_IP_STRING_MAX_LENGTH]; tox_group_peer_get_ip_address(tox, groupnumber, peer_id, ip_str, &err); ip_str[length] = '\0'; ck_assert_msg(err == TOX_ERR_GROUP_PEER_QUERY_OK, "failed to get ip address: error %d", err); fprintf(stderr, "%s\n", ip_str); } static bool all_group_peers_connected(AutoTox *autotoxes, uint32_t tox_count, uint32_t groupnumber, size_t name_length) { for (size_t i = 0; i < tox_count; ++i) { // make sure we got an invite response if (tox_group_get_name_size(autotoxes[i].tox, groupnumber, nullptr) != name_length) { return false; } // make sure we got a sync response if (tox_group_get_peer_limit(autotoxes[i].tox, groupnumber, nullptr) != PEER_LIMIT) { return false; } // make sure we're actually connected if (!tox_group_is_connected(autotoxes[i].tox, groupnumber, nullptr)) { return false; } } return true; } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t groupnumber = tox_event_group_peer_join_get_group_number(event); const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); // we do a connection test here for fun Tox_Err_Group_Peer_Query pq_err; Tox_Connection connection_status = tox_group_peer_get_connection_status(autotox->tox, groupnumber, peer_id, &pq_err); ck_assert(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(connection_status != TOX_CONNECTION_NONE); Tox_Group_Role role = tox_group_peer_get_role(autotox->tox, groupnumber, peer_id, &pq_err); ck_assert_msg(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK, "%d", pq_err); Tox_User_Status status = tox_group_peer_get_status(autotox->tox, groupnumber, peer_id, &pq_err); ck_assert_msg(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK, "%d", pq_err); size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, groupnumber, peer_id, &pq_err); char peer_name[TOX_MAX_NAME_LENGTH + 1]; ck_assert(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); tox_group_peer_get_name(autotox->tox, groupnumber, peer_id, (uint8_t *)peer_name, &pq_err); ck_assert(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK); peer_name[peer_name_len] = 0; // make sure we see the correct peer state on join if (!state->is_founder) { ck_assert_msg(role == TOX_GROUP_ROLE_FOUNDER, "wrong role: %d", role); if (state->peer_joined_count == 0) { ck_assert_msg(status == TOX_USER_STATUS_NONE, "wrong status: %d", status); ck_assert_msg(peer_name_len == PEER0_NICK_LEN, "wrong nick: %s", peer_name); ck_assert(memcmp(peer_name, PEER0_NICK, peer_name_len) == 0); } else { ck_assert_msg(status == TOX_USER_STATUS_BUSY, "wrong status: %d", status); ck_assert(peer_name_len == PEER0_NICK2_LEN); ck_assert(memcmp(peer_name, PEER0_NICK2, peer_name_len) == 0); } } else { ck_assert_msg(role == TOX_GROUP_ROLE_USER, "wrong role: %d", role); ck_assert(peer_name_len == PEER1_NICK_LEN); ck_assert(memcmp(peer_name, PEER1_NICK, peer_name_len) == 0); if (state->peer_joined_count == 0) { ck_assert_msg(status == TOX_USER_STATUS_NONE, "wrong status: %d", status); } else { ck_assert_msg(status == TOX_USER_STATUS_AWAY, "wrong status: %d", status); } } fprintf(stderr, "%s joined with IP: ", peer_name); print_ip(autotox->tox, groupnumber, peer_id); state->peer_id = peer_id; ++state->peer_joined_count; } static void group_peer_self_join_handler(const Tox_Event_Group_Self_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t groupnumber = tox_event_group_self_join_get_group_number(event); // make sure we see our own correct peer state on join callback Tox_Err_Group_Self_Query sq_err; size_t self_length = tox_group_self_get_name_size(autotox->tox, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); uint8_t self_name[TOX_MAX_NAME_LENGTH]; tox_group_self_get_name(autotox->tox, groupnumber, self_name, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_User_Status self_status = tox_group_self_get_status(autotox->tox, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_Group_Role self_role = tox_group_self_get_role(autotox->tox, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (state->is_founder) { // founder doesn't get a self join callback on initial creation of group ck_assert(self_length == PEER0_NICK2_LEN); ck_assert(memcmp(self_name, PEER0_NICK2, self_length) == 0); ck_assert(self_status == TOX_USER_STATUS_BUSY); ck_assert(self_role == TOX_GROUP_ROLE_FOUNDER); } else { ck_assert(self_length == PEER1_NICK_LEN); ck_assert(memcmp(self_name, PEER1_NICK, self_length) == 0); ck_assert(self_role == TOX_GROUP_ROLE_USER); ck_assert(self_status == TOX_USER_STATUS_NONE); } // make sure we see correct group state on join callback uint8_t group_name[GROUP_NAME_LEN]; uint8_t topic[TOX_GROUP_MAX_TOPIC_LENGTH]; ck_assert(tox_group_get_peer_limit(autotox->tox, groupnumber, nullptr) == PEER_LIMIT); ck_assert(tox_group_get_name_size(autotox->tox, groupnumber, nullptr) == GROUP_NAME_LEN); ck_assert(tox_group_get_topic_size(autotox->tox, groupnumber, nullptr) == TOPIC_LEN); Tox_Err_Group_State_Query query_err; tox_group_get_name(autotox->tox, groupnumber, group_name, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%d", query_err); ck_assert(memcmp(group_name, GROUP_NAME, GROUP_NAME_LEN) == 0); tox_group_get_topic(autotox->tox, groupnumber, topic, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%d", query_err); ck_assert(memcmp(topic, TOPIC, TOPIC_LEN) == 0); uint32_t peer_id = tox_group_self_get_peer_id(autotox->tox, groupnumber, nullptr); fprintf(stderr, "self joined with IP: "); print_ip(autotox->tox, groupnumber, peer_id); ++state->self_joined_count; } static void group_peer_exit_handler(const Tox_Event_Group_Peer_Exit *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint8_t *part_message = tox_event_group_peer_exit_get_part_message(event); const size_t length = tox_event_group_peer_exit_get_part_message_length(event); ++state->peer_exit_count; // first exit is a disconnect. second is a real exit with a part message if (state->peer_exit_count == 2) { ck_assert(length == EXIT_MESSAGE_LEN); ck_assert(memcmp(part_message, EXIT_MESSAGE, length) == 0); } } static void group_peer_name_handler(const Tox_Event_Group_Peer_Name *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint8_t *name = tox_event_group_peer_name_get_name(event); const size_t length = tox_event_group_peer_name_get_name_length(event); // note: we already test the name_get api call elsewhere ck_assert(length == PEER0_NICK2_LEN); ck_assert(memcmp(name, PEER0_NICK2, length) == 0); state->peer_nick = true; } static void group_peer_status_handler(const Tox_Event_Group_Peer_Status *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t groupnumber = tox_event_group_peer_status_get_group_number(event); const uint32_t peer_id = tox_event_group_peer_status_get_peer_id(event); const Tox_User_Status status = tox_event_group_peer_status_get_status(event); Tox_Err_Group_Peer_Query err; Tox_User_Status cur_status = tox_group_peer_get_status(autotox->tox, groupnumber, peer_id, &err); ck_assert_msg(cur_status == status, "%d, %d", cur_status, status); ck_assert(status == TOX_USER_STATUS_BUSY); state->peer_status = true; } static void group_announce_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES == 2, "NUM_GROUP_TOXES needs to be 2"); Tox *tox0 = autotoxes[0].tox; Tox *tox1 = autotoxes[1].tox; State *state0 = (State *)autotoxes[0].state; const State *state1 = (const State *)autotoxes[1].state; tox_events_callback_group_peer_join(autotoxes[0].dispatch, group_peer_join_handler); tox_events_callback_group_peer_join(autotoxes[1].dispatch, group_peer_join_handler); tox_events_callback_group_self_join(autotoxes[0].dispatch, group_peer_self_join_handler); tox_events_callback_group_self_join(autotoxes[1].dispatch, group_peer_self_join_handler); tox_events_callback_group_peer_name(autotoxes[1].dispatch, group_peer_name_handler); tox_events_callback_group_peer_status(autotoxes[1].dispatch, group_peer_status_handler); tox_events_callback_group_peer_exit(autotoxes[1].dispatch, group_peer_exit_handler); // tox0 makes new group. Tox_Err_Group_New err_new; uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *) GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, &err_new); ck_assert(err_new == TOX_ERR_GROUP_NEW_OK); state0->is_founder = true; iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); // changes the state (for sync check purposes) Tox_Err_Group_Set_Peer_Limit limit_set_err; tox_group_set_peer_limit(tox0, groupnumber, PEER_LIMIT, &limit_set_err); ck_assert_msg(limit_set_err == TOX_ERR_GROUP_SET_PEER_LIMIT_OK, "failed to set peer limit: %d", limit_set_err); Tox_Err_Group_Topic_Set tp_err; tox_group_set_topic(tox0, groupnumber, (const uint8_t *)TOPIC, TOPIC_LEN, &tp_err); ck_assert(tp_err == TOX_ERR_GROUP_TOPIC_SET_OK); // get the chat id of the new group. Tox_Err_Group_State_Query err_id; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, groupnumber, chat_id, &err_id); ck_assert(err_id == TOX_ERR_GROUP_STATE_QUERY_OK); // tox1 joins it. Tox_Err_Group_Join err_join; tox_group_join(tox1, chat_id, (const uint8_t *)PEER1_NICK, PEER1_NICK_LEN, nullptr, 0, &err_join); ck_assert(err_join == TOX_ERR_GROUP_JOIN_OK); // peers see each other and themselves join while (!state1->peer_joined_count || !state1->self_joined_count || !state0->peer_joined_count) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } // wait for group syncing to finish while (!all_group_peers_connected(autotoxes, NUM_GROUP_TOXES, groupnumber, GROUP_NAME_LEN)) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } fprintf(stderr, "Peers connected to group\n"); // tox 0 changes name Tox_Err_Group_Self_Name_Set n_err; tox_group_self_set_name(tox0, groupnumber, (const uint8_t *)PEER0_NICK2, PEER0_NICK2_LEN, &n_err); ck_assert(n_err == TOX_ERR_GROUP_SELF_NAME_SET_OK); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); Tox_Err_Group_Self_Query sq_err; size_t self_length = tox_group_self_get_name_size(tox0, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_length == PEER0_NICK2_LEN); uint8_t self_name[TOX_MAX_NAME_LENGTH]; tox_group_self_get_name(tox0, groupnumber, self_name, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(self_name, PEER0_NICK2, self_length) == 0); fprintf(stderr, "Peer 0 successfully changed nick\n"); // tox 0 changes status Tox_Err_Group_Self_Status_Set s_err; tox_group_self_set_status(tox0, groupnumber, TOX_USER_STATUS_BUSY, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_STATUS_SET_OK); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); Tox_User_Status self_status = tox_group_self_get_status(tox0, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_status == TOX_USER_STATUS_BUSY); fprintf(stderr, "Peer 0 successfully changed status to %d\n", self_status); while (!state1->peer_nick && !state1->peer_status) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } // tox 0 and tox 1 should see the same public key for tox 0 uint8_t tox0_self_pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; tox_group_self_get_public_key(tox0, groupnumber, tox0_self_pk, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_Err_Group_Peer_Query pq_err; uint8_t tox0_pk_query[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; tox_group_peer_get_public_key(tox1, groupnumber, state1->peer_id, tox0_pk_query, &pq_err); ck_assert(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(memcmp(tox0_pk_query, tox0_self_pk, TOX_GROUP_PEER_PUBLIC_KEY_SIZE) == 0); fprintf(stderr, "Peer 0 disconnecting...\n"); // tox 0 disconnects then reconnects Tox_Err_Group_Disconnect d_err; tox_group_disconnect(tox0, groupnumber, &d_err); ck_assert(d_err == TOX_ERR_GROUP_DISCONNECT_OK); while (state1->peer_exit_count != 1) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } // tox 1 changes status while alone in the group tox_group_self_set_status(tox1, groupnumber, TOX_USER_STATUS_AWAY, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_STATUS_SET_OK); fprintf(stderr, "Peer 0 reconnecting...\n"); Tox_Err_Group_Reconnect r_err; tox_group_reconnect(tox0, groupnumber, &r_err); ck_assert(r_err == TOX_ERR_GROUP_RECONNECT_OK); while (state1->peer_joined_count != 2 && state0->self_joined_count == 2) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } for (size_t i = 0; i < 100; ++i) { // if we don't do this the exit packet never arrives iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_group_peers_connected(autotoxes, NUM_GROUP_TOXES, groupnumber, GROUP_NAME_LEN)) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } // tox 0 should have the same public key and still be founder uint8_t tox0_self_pk2[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; tox_group_self_get_public_key(tox0, groupnumber, tox0_self_pk2, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(tox0_self_pk2, tox0_self_pk, TOX_GROUP_PEER_PUBLIC_KEY_SIZE) == 0); Tox_Group_Role self_role = tox_group_self_get_role(tox0, groupnumber, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_Group_Role other_role = tox_group_peer_get_role(tox1, groupnumber, state1->peer_id, &pq_err); ck_assert(pq_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(self_role == other_role && self_role == TOX_GROUP_ROLE_FOUNDER); uint32_t num_groups1 = tox_group_get_number_groups(tox0); uint32_t num_groups2 = tox_group_get_number_groups(tox1); ck_assert(num_groups1 == num_groups2 && num_groups2 == 1); fprintf(stderr, "Both peers exiting group...\n"); Tox_Err_Group_Leave err_exit; tox_group_leave(tox0, groupnumber, (const uint8_t *)EXIT_MESSAGE, EXIT_MESSAGE_LEN, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); while (state1->peer_exit_count != 2) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } tox_group_leave(tox1, groupnumber, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); while (num_groups1 != 0 || num_groups2 != 0) { num_groups1 = tox_group_get_number_groups(tox0); num_groups2 = tox_group_get_number_groups(tox1); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, NUM_GROUP_TOXES, group_announce_test, sizeof(State), &options); return 0; } #undef NUM_GROUP_TOXES #undef PEER1_NICK #undef PEER0_NICK #undef PEER0_NICK_LEN #undef PEER1_NICK_LEN #undef GROUP_NAME #undef GROUP_NAME_LEN #undef PEER_LIMIT #undef TOPIC #undef TOPIC_LEN c-toxcore-0.2.20/auto_tests/group_invite_test.c0000644060175106017510000002336114714247532017613 0ustar robin/* * Tests group invites as well as join restrictions, including password protection, privacy state, * and peer limits. Ensures sure that the peer being blocked from joining successfully receives * the invite fail packet with the correct message. * * This test also checks that many peers can successfully join the group simultaneously. */ #include #include #include #include "auto_test_support.h" #include "check_compat.h" typedef struct State { uint32_t num_peers; bool peer_limit_fail; bool password_fail; bool connected; size_t messages_received; } State; #define NUM_GROUP_TOXES 8 // must be > 7 #define PASSWORD "dadada" #define PASS_LEN (sizeof(PASSWORD) - 1) #define WRONG_PASS "dadadada" #define WRONG_PASS_LEN (sizeof(WRONG_PASS) - 1) static bool group_has_full_graph(const AutoTox *autotoxes, uint32_t group_number, uint32_t expected_peer_count) { for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; if (state->num_peers < expected_peer_count) { return false; } } const State *state0 = (const State *)autotoxes[0].state; const State *state1 = (const State *)autotoxes[1].state; const State *state5 = (const State *)autotoxes[5].state; if (state0->num_peers < expected_peer_count || state1->num_peers < expected_peer_count || state5->num_peers < expected_peer_count) { return false; } return true; } static void group_join_fail_handler(const Tox_Event_Group_Join_Fail *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const Tox_Group_Join_Fail fail_type = tox_event_group_join_fail_get_fail_type(event); switch (fail_type) { case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: { state->peer_limit_fail = true; break; } case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: { state->password_fail = true; break; } case TOX_GROUP_JOIN_FAIL_UNKNOWN: // intentional fallthrough default: { ck_assert_msg(false, "Got unknown join fail"); return; } } } static void group_self_join_handler(const Tox_Event_Group_Self_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; state->connected = true; } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ++state->num_peers; ck_assert(state->num_peers < NUM_GROUP_TOXES); } static void group_invite_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES > 7, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); tox_events_callback_group_join_fail(autotoxes[i].dispatch, group_join_fail_handler); tox_events_callback_group_self_join(autotoxes[i].dispatch, group_self_join_handler); } Tox *tox0 = autotoxes[0].tox; Tox *tox1 = autotoxes[1].tox; Tox *tox2 = autotoxes[2].tox; Tox *tox3 = autotoxes[3].tox; Tox *tox4 = autotoxes[4].tox; Tox *tox5 = autotoxes[5].tox; Tox *tox6 = autotoxes[6].tox; const State *state0 = (const State *)autotoxes[0].state; const State *state2 = (const State *)autotoxes[2].state; const State *state3 = (const State *)autotoxes[3].state; const State *state4 = (const State *)autotoxes[4].state; const State *state5 = (const State *)autotoxes[5].state; const State *state6 = (const State *)autotoxes[6].state; Tox_Err_Group_New new_err; uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4, (const uint8_t *)"test", 4, &new_err); ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, groupnumber, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%d", id_err); // peer 1 joins public group with no password Tox_Err_Group_Join join_err; tox_group_join(tox1, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); while (state0->num_peers < 1) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Peer 1 joined group\n"); // founder sets a password Tox_Err_Group_Set_Password pass_set_err; tox_group_set_password(tox0, groupnumber, (const uint8_t *)PASSWORD, PASS_LEN, &pass_set_err); ck_assert_msg(pass_set_err == TOX_ERR_GROUP_SET_PASSWORD_OK, "%d", pass_set_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000); // peer 2 attempts to join with no password tox_group_join(tox2, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); while (!state2->password_fail) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Peer 2 successfully blocked with no password\n"); // peer 3 attempts to join with invalid password tox_group_join(tox3, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)WRONG_PASS, WRONG_PASS_LEN, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); while (!state3->password_fail) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Peer 3 successfully blocked with invalid password\n"); // founder sets peer limit to 1 Tox_Err_Group_Set_Peer_Limit limit_set_err; tox_group_set_peer_limit(tox0, groupnumber, 1, &limit_set_err); ck_assert_msg(limit_set_err == TOX_ERR_GROUP_SET_PEER_LIMIT_OK, "%d", limit_set_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000); // peer 4 attempts to join with correct password tox_group_join(tox4, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)PASSWORD, PASS_LEN, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); while (!state4->peer_limit_fail) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Peer 4 successfully blocked from joining full group\n"); // founder removes password and increases peer limit to 100 tox_group_set_password(tox0, groupnumber, nullptr, 0, &pass_set_err); ck_assert_msg(pass_set_err == TOX_ERR_GROUP_SET_PASSWORD_OK, "%d", pass_set_err); tox_group_set_peer_limit(tox0, groupnumber, 100, &limit_set_err); ck_assert_msg(limit_set_err == TOX_ERR_GROUP_SET_PEER_LIMIT_OK, "%d", limit_set_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000); // peer 5 attempts to join group tox_group_join(tox5, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); while (!state5->connected) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Peer 5 successfully joined the group\n"); // founder makes group private Tox_Err_Group_Set_Privacy_State priv_err; tox_group_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PRIVATE, &priv_err); ck_assert_msg(priv_err == TOX_ERR_GROUP_SET_PRIVACY_STATE_OK, "%d", priv_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 5000); // peer 6 attempts to join group via chat ID tox_group_join(tox6, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); // since we don't receive a fail packet in this case we just wait a while and check if we're in the group iterate_all_wait(autotoxes, NUM_GROUP_TOXES, 20000); ck_assert(!state6->connected); printf("Peer 6 failed to join private group via chat ID\n"); // founder makes group public again tox_group_set_privacy_state(tox0, groupnumber, TOX_GROUP_PRIVACY_STATE_PUBLIC, &priv_err); ck_assert_msg(priv_err == TOX_ERR_GROUP_SET_PRIVACY_STATE_OK, "%d", priv_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); const uint32_t num_new_peers = NUM_GROUP_TOXES - 7; printf("Connecting %u peers at the same time\n", num_new_peers); for (size_t i = 7; i < NUM_GROUP_TOXES; ++i) { tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); } const uint32_t expected_peer_count = num_new_peers + state0->num_peers + 1; while (!group_has_full_graph(autotoxes, groupnumber, expected_peer_count)) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("Every peer sees every other peer\n"); for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[i].tox, 0, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); } printf("All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_invite_test, sizeof(State), &autotest_opts); return 0; } #undef NUM_GROUP_TOXES #undef PASSWORD #undef PASS_LEN #undef WRONG_PASS #undef WRONG_PASS_LEN c-toxcore-0.2.20/auto_tests/group_message_test.c0000644060175106017510000006350114714247532017741 0ustar robin/* * Tests message sending capabilities, including: * - The ability to send/receive plain, action, and custom messages * - The lossless UDP implementation * - The packet splitting implementation * - The ignore feature */ #include #include #include #include "auto_test_support.h" #include "check_compat.h" #include "../toxcore/util.h" typedef struct State { uint32_t peer_id; bool peer_joined; bool message_sent; bool message_received; Tox_Group_Message_Id pseudo_msg_id; bool private_message_received; size_t custom_packets_received; size_t custom_private_packets_received; bool lossless_check; bool wraparound_check; int32_t last_msg_recv; } State; #define NUM_GROUP_TOXES 2 #define MAX_NUM_MESSAGES_LOSSLESS_TEST 300 #define MAX_NUM_MESSAGES_WRAPAROUND_TEST 9001 #define TEST_MESSAGE "Where is it I've read that someone condemned to death says or thinks, an hour before his death, that if he had to live on some high rock, on such a narrow ledge that he'd only room to stand, and the ocean, everlasting darkness, everlasting solitude, everlasting tempest around him, if he had to remain standing on a square yard of space all his life, a thousand years, eternity, it were better to live so than to die at once. Only to live, to live and live! Life, whatever it may be!" #define TEST_MESSAGE_LEN (sizeof(TEST_MESSAGE) - 1) #define TEST_GROUP_NAME "Utah Data Center" #define TEST_GROUP_NAME_LEN (sizeof(TEST_GROUP_NAME) - 1) #define TEST_PRIVATE_MESSAGE "Don't spill yer beans" #define TEST_PRIVATE_MESSAGE_LEN (sizeof(TEST_PRIVATE_MESSAGE) - 1) #define TEST_CUSTOM_PACKET "Why'd ya spill yer beans?" #define TEST_CUSTOM_PACKET_LEN (sizeof(TEST_CUSTOM_PACKET) - 1) #define TEST_CUSTOM_PACKET_LARGE "Where is it I've read that someone condemned to death says or thinks, an hour before his death, that if he had to live on some high rock, on such a narrow ledge that he'd only room to stand, and the ocean, everlasting darkness, everlasting solitude, everlasting tempest around him, if he had to remain standing on a square yard of space all his life, a thousand years, eternity, it were better to live so than to die at once. Only to live, to live and live! Life, whatever it may be! ...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................0123456789" #define TEST_CUSTOM_PACKET_LARGE_LEN (sizeof(TEST_CUSTOM_PACKET_LARGE) - 1) static_assert(TEST_CUSTOM_PACKET_LARGE_LEN == TOX_GROUP_MAX_CUSTOM_LOSSY_PACKET_LENGTH, "Should be max"); #define TEST_CUSTOM_PRIVATE_PACKET "This is a custom private packet. Enjoy." #define TEST_CUSTOM_PRIVATE_PACKET_LEN (sizeof(TEST_CUSTOM_PRIVATE_PACKET) - 1) #define IGNORE_MESSAGE "Am I bothering you?" #define IGNORE_MESSAGE_LEN (sizeof(IGNORE_MESSAGE) - 1) #define PEER0_NICK "Thomas" #define PEER0_NICK_LEN (sizeof(PEER0_NICK) - 1) #define PEER1_NICK "Winslow" #define PEER1_NICK_LEN (sizeof(PEER1_NICK) - 1) static uint16_t get_message_checksum(const uint8_t *message, uint16_t length) { uint16_t sum = 0; for (size_t i = 0; i < length; ++i) { sum += message[i]; } return sum; } static void group_invite_handler(const Tox_Event_Group_Invite *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t friend_number = tox_event_group_invite_get_friend_number(event); const uint8_t *invite_data = tox_event_group_invite_get_invite_data(event); const size_t length = tox_event_group_invite_get_invite_data_length(event); printf("invite arrived; accepting\n"); Tox_Err_Group_Invite_Accept err_accept; tox_group_invite_accept(autotox->tox, friend_number, invite_data, length, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, nullptr, 0, &err_accept); ck_assert(err_accept == TOX_ERR_GROUP_INVITE_ACCEPT_OK); } static void group_join_fail_handler(const Tox_Event_Group_Join_Fail *event, void *user_data) { const Tox_Group_Join_Fail fail_type = tox_event_group_join_fail_get_fail_type(event); printf("join failed: %d\n", fail_type); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); ck_assert_msg(state->peer_joined == false, "Peer timedout"); printf("peer %u joined, sending message\n", peer_id); state->peer_joined = true; state->peer_id = peer_id; } static void group_custom_private_packet_handler(const Tox_Event_Group_Custom_Private_Packet *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_custom_private_packet_get_group_number(event); const uint32_t peer_id = tox_event_group_custom_private_packet_get_peer_id(event); const uint8_t *data = tox_event_group_custom_private_packet_get_data(event); const size_t length = tox_event_group_custom_private_packet_get_data_length(event); ck_assert_msg(length == TEST_CUSTOM_PRIVATE_PACKET_LEN, "Failed to receive custom private packet. Invalid length: %zu\n", length); char message_buf[TOX_MAX_CUSTOM_PACKET_SIZE + 1]; memcpy(message_buf, data, length); message_buf[length] = 0; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, groupnumber, peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); char peer_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_peer_get_name(autotox->tox, groupnumber, peer_id, (uint8_t *) peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(memcmp(peer_name, PEER0_NICK, peer_name_len) == 0); Tox_Err_Group_Self_Query s_err; size_t self_name_len = tox_group_self_get_name_size(autotox->tox, groupnumber, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_name_len <= TOX_MAX_NAME_LENGTH); char self_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_self_get_name(autotox->tox, groupnumber, (uint8_t *)self_name, &s_err); self_name[self_name_len] = 0; ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(self_name, PEER1_NICK, self_name_len) == 0); printf("%s sent custom private packet to %s: %s\n", peer_name, self_name, message_buf); ck_assert(memcmp(message_buf, TEST_CUSTOM_PRIVATE_PACKET, length) == 0); State *state = (State *)autotox->state; ++state->custom_private_packets_received; } static void group_custom_packet_handler(const Tox_Event_Group_Custom_Packet *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_custom_packet_get_group_number(event); const uint32_t peer_id = tox_event_group_custom_packet_get_peer_id(event); const uint8_t *data = tox_event_group_custom_packet_get_data(event); const size_t length = tox_event_group_custom_packet_get_data_length(event); ck_assert_msg(length == TEST_CUSTOM_PACKET_LEN, "Failed to receive custom packet. Invalid length: %zu\n", length); char message_buf[TOX_MAX_CUSTOM_PACKET_SIZE + 1]; memcpy(message_buf, data, length); message_buf[length] = 0; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, groupnumber, peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); char peer_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_peer_get_name(autotox->tox, groupnumber, peer_id, (uint8_t *)peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(memcmp(peer_name, PEER0_NICK, peer_name_len) == 0); Tox_Err_Group_Self_Query s_err; size_t self_name_len = tox_group_self_get_name_size(autotox->tox, groupnumber, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_name_len <= TOX_MAX_NAME_LENGTH); char self_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_self_get_name(autotox->tox, groupnumber, (uint8_t *)self_name, &s_err); self_name[self_name_len] = 0; ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(self_name, PEER1_NICK, self_name_len) == 0); printf("%s sent custom packet to %s: %s\n", peer_name, self_name, message_buf); ck_assert(memcmp(message_buf, TEST_CUSTOM_PACKET, length) == 0); State *state = (State *)autotox->state; ++state->custom_packets_received; } static void group_custom_packet_large_handler(const Tox_Event_Group_Custom_Packet *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint8_t *data = tox_event_group_custom_packet_get_data(event); const size_t length = tox_event_group_custom_packet_get_data_length(event); ck_assert_msg(length == TEST_CUSTOM_PACKET_LARGE_LEN, "Failed to receive large custom packet. Invalid length: %zu\n", length); ck_assert(memcmp(data, TEST_CUSTOM_PACKET_LARGE, length) == 0); State *state = (State *)autotox->state; ++state->custom_packets_received; } static void group_message_handler(const Tox_Event_Group_Message *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_message_get_group_number(event); const uint32_t peer_id = tox_event_group_message_get_peer_id(event); const uint8_t *message = tox_event_group_message_get_message(event); const size_t length = tox_event_group_message_get_message_length(event); const uint32_t pseudo_msg_id = tox_event_group_message_get_message_id(event); ck_assert(!(length == IGNORE_MESSAGE_LEN && memcmp(message, IGNORE_MESSAGE, length) == 0)); ck_assert_msg(length == TEST_MESSAGE_LEN, "Failed to receive message. Invalid length: %zu\n", length); char message_buf[TOX_GROUP_MAX_MESSAGE_LENGTH + 1]; memcpy(message_buf, message, length); message_buf[length] = 0; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, groupnumber, peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); char peer_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_peer_get_name(autotox->tox, groupnumber, peer_id, (uint8_t *)peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(memcmp(peer_name, PEER0_NICK, peer_name_len) == 0); Tox_Err_Group_Self_Query s_err; size_t self_name_len = tox_group_self_get_name_size(autotox->tox, groupnumber, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_name_len <= TOX_MAX_NAME_LENGTH); char self_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_self_get_name(autotox->tox, groupnumber, (uint8_t *)self_name, &s_err); self_name[self_name_len] = 0; ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(self_name, PEER1_NICK, self_name_len) == 0); printf("%s sent message to %s:(id:%u) %s\n", peer_name, self_name, pseudo_msg_id, message_buf); ck_assert(memcmp(message_buf, TEST_MESSAGE, length) == 0); State *state = (State *)autotox->state; state->message_received = true; state->pseudo_msg_id = pseudo_msg_id; } static void group_private_message_handler(const Tox_Event_Group_Private_Message *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_private_message_get_group_number(event); const uint32_t peer_id = tox_event_group_private_message_get_peer_id(event); const Tox_Message_Type type = tox_event_group_private_message_get_message_type(event); const uint8_t *message = tox_event_group_private_message_get_message(event); const size_t length = tox_event_group_private_message_get_message_length(event); const Tox_Group_Message_Id pseudo_msg_id = tox_event_group_private_message_get_message_id(event); ck_assert_msg(length == TEST_PRIVATE_MESSAGE_LEN, "Failed to receive message. Invalid length: %zu\n", length); char message_buf[TOX_GROUP_MAX_MESSAGE_LENGTH + 1]; memcpy(message_buf, message, length); message_buf[length] = 0; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, groupnumber, peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); char peer_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_peer_get_name(autotox->tox, groupnumber, peer_id, (uint8_t *)peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(memcmp(peer_name, PEER0_NICK, peer_name_len) == 0); Tox_Err_Group_Self_Query s_err; size_t self_name_len = tox_group_self_get_name_size(autotox->tox, groupnumber, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_name_len <= TOX_MAX_NAME_LENGTH); char self_name[TOX_MAX_NAME_LENGTH + 1]; tox_group_self_get_name(autotox->tox, groupnumber, (uint8_t *)self_name, &s_err); self_name[self_name_len] = 0; ck_assert(s_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(memcmp(self_name, PEER1_NICK, self_name_len) == 0); printf("%s sent private action to %s:(id: %u) %s\n", peer_name, self_name, pseudo_msg_id, message_buf); ck_assert(memcmp(message_buf, TEST_PRIVATE_MESSAGE, length) == 0); ck_assert(type == TOX_MESSAGE_TYPE_ACTION); State *state = (State *)autotox->state; state->private_message_received = true; state->pseudo_msg_id = pseudo_msg_id; } static void group_message_handler_lossless_test(const Tox_Event_Group_Message *event, void *user_data) { const uint8_t *message = tox_event_group_message_get_message(event); const size_t length = tox_event_group_message_get_message_length(event); AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ck_assert(length >= 4 && length <= TOX_GROUP_MAX_MESSAGE_LENGTH); uint16_t start; uint16_t checksum; memcpy(&start, message, sizeof(uint16_t)); memcpy(&checksum, message + sizeof(uint16_t), sizeof(uint16_t)); ck_assert_msg(start == state->last_msg_recv + 1, "Expected %d, got start %u", state->last_msg_recv + 1, start); ck_assert_msg(checksum == get_message_checksum(message + 4, length - 4), "Wrong checksum"); state->last_msg_recv = start; if (state->last_msg_recv == MAX_NUM_MESSAGES_LOSSLESS_TEST) { state->lossless_check = true; } } static void group_message_handler_wraparound_test(const Tox_Event_Group_Message *event, void *user_data) { const uint8_t *message = tox_event_group_message_get_message(event); const size_t length = tox_event_group_message_get_message_length(event); AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ck_assert(length == 2); uint16_t num; memcpy(&num, message, sizeof(uint16_t)); ck_assert_msg(num == state->last_msg_recv + 1, "Expected %d, got start %u", state->last_msg_recv + 1, num); state->last_msg_recv = num; if (state->last_msg_recv == MAX_NUM_MESSAGES_WRAPAROUND_TEST) { state->wraparound_check = true; } } static void group_message_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES >= 2, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); const Random *rng = os_random(); ck_assert(rng != nullptr); Tox *tox0 = autotoxes[0].tox; const Tox *tox1 = autotoxes[1].tox; State *state0 = (State *)autotoxes[0].state; State *state1 = (State *)autotoxes[1].state; // initialize to different values state0->pseudo_msg_id = 0; state1->pseudo_msg_id = 1; tox_events_callback_group_invite(autotoxes[1].dispatch, group_invite_handler); tox_events_callback_group_join_fail(autotoxes[1].dispatch, group_join_fail_handler); tox_events_callback_group_peer_join(autotoxes[1].dispatch, group_peer_join_handler); tox_events_callback_group_join_fail(autotoxes[0].dispatch, group_join_fail_handler); tox_events_callback_group_peer_join(autotoxes[0].dispatch, group_peer_join_handler); tox_events_callback_group_message(autotoxes[0].dispatch, group_message_handler); tox_events_callback_group_custom_packet(autotoxes[0].dispatch, group_custom_packet_handler); tox_events_callback_group_custom_private_packet(autotoxes[0].dispatch, group_custom_private_packet_handler); tox_events_callback_group_private_message(autotoxes[0].dispatch, group_private_message_handler); Tox_Err_Group_Send_Message err_send; fprintf(stderr, "Tox 0 creates new group and invites tox1...\n"); // tox0 makes new group. Tox_Err_Group_New err_new; const uint32_t group_number = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PRIVATE, (const uint8_t *)TEST_GROUP_NAME, TEST_GROUP_NAME_LEN, (const uint8_t *)PEER1_NICK, PEER1_NICK_LEN, &err_new); ck_assert(err_new == TOX_ERR_GROUP_NEW_OK); // tox0 invites tox1 Tox_Err_Group_Invite_Friend err_invite; tox_group_invite_friend(tox0, group_number, 0, &err_invite); ck_assert(err_invite == TOX_ERR_GROUP_INVITE_FRIEND_OK); while (!state0->message_received) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); if (state1->peer_joined && !state1->message_sent) { state1->pseudo_msg_id = tox_group_send_message( tox1, group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)TEST_MESSAGE, TEST_MESSAGE_LEN, &err_send); ck_assert(err_send == TOX_ERR_GROUP_SEND_MESSAGE_OK); state1->message_sent = true; } } ck_assert_msg(state0->pseudo_msg_id == state1->pseudo_msg_id, "id0:%u id1:%u", state0->pseudo_msg_id, state1->pseudo_msg_id); // Make sure we're still connected to each friend Tox_Connection conn_1 = tox_friend_get_connection_status(tox0, 0, nullptr); Tox_Connection conn_2 = tox_friend_get_connection_status(tox1, 0, nullptr); ck_assert(conn_1 != TOX_CONNECTION_NONE && conn_2 != TOX_CONNECTION_NONE); // tox0 ignores tox1 Tox_Err_Group_Set_Ignore ig_err; tox_group_set_ignore(tox0, group_number, state0->peer_id, true, &ig_err); ck_assert_msg(ig_err == TOX_ERR_GROUP_SET_IGNORE_OK, "%d", ig_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); // tox1 sends group a message which should not be seen by tox0's message handler tox_group_send_message(tox1, group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)IGNORE_MESSAGE, IGNORE_MESSAGE_LEN, &err_send); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); // tox0 unignores tox1 tox_group_set_ignore(tox0, group_number, state0->peer_id, false, &ig_err); ck_assert_msg(ig_err == TOX_ERR_GROUP_SET_IGNORE_OK, "%d", ig_err); fprintf(stderr, "Sending private action...\n"); // tox1 sends a private action to tox0 Tox_Err_Group_Send_Private_Message m_err; state1->pseudo_msg_id = tox_group_send_private_message(tox1, group_number, state1->peer_id, TOX_MESSAGE_TYPE_ACTION, (const uint8_t *)TEST_PRIVATE_MESSAGE, TEST_PRIVATE_MESSAGE_LEN, &m_err); ck_assert_msg(m_err == TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK, "%d", m_err); while (!state0->private_message_received) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } ck_assert_msg(state0->pseudo_msg_id == state1->pseudo_msg_id, "id0:%u id1:%u", state0->pseudo_msg_id, state1->pseudo_msg_id); fprintf(stderr, "Sending custom packets...\n"); // tox0 sends a lossless and lossy custom packet to tox1 Tox_Err_Group_Send_Custom_Packet c_err; tox_group_send_custom_packet(tox1, group_number, true, (const uint8_t *)TEST_CUSTOM_PACKET, TEST_CUSTOM_PACKET_LEN, &c_err); ck_assert_msg(c_err == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK, "%d", c_err); tox_group_send_custom_packet(tox1, group_number, false, (const uint8_t *)TEST_CUSTOM_PACKET, TEST_CUSTOM_PACKET_LEN, &c_err); ck_assert_msg(c_err == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK, "%d", c_err); fprintf(stderr, "Sending custom private packets...\n"); // tox0 sends a lossless and lossy custom private packet to tox1 Tox_Err_Group_Send_Custom_Private_Packet cperr; tox_group_send_custom_private_packet(tox1, group_number, state1->peer_id, true, (const uint8_t *)TEST_CUSTOM_PRIVATE_PACKET, TEST_CUSTOM_PRIVATE_PACKET_LEN, &cperr); ck_assert_msg(cperr == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK, "%d", cperr); tox_group_send_custom_private_packet(tox1, group_number, state1->peer_id, false, (const uint8_t *)TEST_CUSTOM_PRIVATE_PACKET, TEST_CUSTOM_PRIVATE_PACKET_LEN, &cperr); ck_assert_msg(cperr == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK, "%d", cperr); while (state0->custom_packets_received < 2 || state0->custom_private_packets_received < 2) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } // tox0 sends a large max sized lossy custom packet // overwrite callback for larger packet tox_events_callback_group_custom_packet(autotoxes[0].dispatch, group_custom_packet_large_handler); tox_group_send_custom_packet(tox1, group_number, false, (const uint8_t *)TEST_CUSTOM_PACKET_LARGE, TEST_CUSTOM_PACKET_LARGE_LEN, &c_err); ck_assert_msg(c_err == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK, "%d", c_err); while (state0->custom_packets_received < 3) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } uint8_t m[TOX_GROUP_MAX_MESSAGE_LENGTH] = {0}; fprintf(stderr, "Doing lossless packet test...\n"); tox_events_callback_group_message(autotoxes[1].dispatch, group_message_handler_lossless_test); state1->last_msg_recv = -1; // lossless and packet splitting/reassembly test for (uint16_t i = 0; i <= MAX_NUM_MESSAGES_LOSSLESS_TEST; ++i) { if (i % 10 == 0) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } uint16_t message_size = min_u16(4 + (random_u16(rng) % TOX_GROUP_MAX_MESSAGE_LENGTH), TOX_GROUP_MAX_MESSAGE_LENGTH); memcpy(m, &i, sizeof(uint16_t)); for (size_t j = 4; j < message_size; ++j) { m[j] = random_u32(rng); } const uint16_t checksum = get_message_checksum(m + 4, message_size - 4); memcpy(m + 2, &checksum, sizeof(uint16_t)); tox_group_send_message(tox0, group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)m, message_size, &err_send); ck_assert(err_send == TOX_ERR_GROUP_SEND_MESSAGE_OK); } while (!state1->lossless_check) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } state1->last_msg_recv = -1; tox_events_callback_group_message(autotoxes[1].dispatch, group_message_handler_wraparound_test); fprintf(stderr, "Doing wraparound test...\n"); // packet array wrap-around test for (uint16_t i = 0; i <= MAX_NUM_MESSAGES_WRAPAROUND_TEST; ++i) { if (i % 10 == 0) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } memcpy(m, &i, sizeof(uint16_t)); tox_group_send_message(tox0, group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)m, 2, &err_send); ck_assert(err_send == TOX_ERR_GROUP_SEND_MESSAGE_OK); } while (!state1->wraparound_check) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[i].tox, group_number, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); } fprintf(stderr, "All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_message_test, sizeof(State), &autotest_opts); return 0; } #undef NUM_GROUP_TOXES #undef PEER1_NICK #undef PEER1_NICK_LEN #undef PEER0_NICK #undef PEER0_NICK_LEN #undef TEST_GROUP_NAME #undef TEST_GROUP_NAME_LEN #undef TEST_MESSAGE #undef TEST_MESSAGE_LEN #undef TEST_PRIVATE_MESSAGE_LEN #undef TEST_CUSTOM_PACKET #undef TEST_CUSTOM_PACKET_LEN #undef TEST_CUSTOM_PACKET_LARGE #undef TEST_CUSTOM_PACKET_LARGE_LEN #undef TEST_CUSTOM_PRIVATE_PACKET #undef TEST_CUSTOM_PRIVATE_PACKET_LEN #undef IGNORE_MESSAGE #undef IGNORE_MESSAGE_LEN #undef MAX_NUM_MESSAGES_LOSSLESS_TEST #undef MAX_NUM_MESSAGES_WRAPAROUND_TEST c-toxcore-0.2.20/auto_tests/group_moderation_test.c0000644060175106017510000006001014714247532020446 0ustar robin/* * Tests group moderation functionality. * * Note that making the peer count too high will break things. This test should not be relied on * for general group/syncing functionality. */ #include #include #include #include "auto_test_support.h" #include "check_compat.h" #include "../toxcore/tox.h" #define NUM_GROUP_TOXES 5 #define GROUP_NAME "NASA Headquarters" #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) typedef struct Peer { char name[TOX_MAX_NAME_LENGTH + 1]; size_t name_length; uint32_t peer_id; } Peer; typedef struct State { char self_name[TOX_MAX_NAME_LENGTH + 1]; size_t self_name_length; uint32_t group_number; uint32_t num_peers; Peer peers[NUM_GROUP_TOXES - 1]; bool mod_check; size_t mod_event_count; char mod_name1[TOX_MAX_NAME_LENGTH]; char mod_name2[TOX_MAX_NAME_LENGTH]; bool observer_check; size_t observer_event_count; char observer_name1[TOX_MAX_NAME_LENGTH]; char observer_name2[TOX_MAX_NAME_LENGTH]; bool user_check; size_t user_event_count; bool kick_check; // mod gets kicked } State; static bool all_peers_connected(AutoTox *autotoxes) { for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; if (state->num_peers != NUM_GROUP_TOXES - 1) { return false; } if (!tox_group_is_connected(autotoxes[i].tox, state->group_number, nullptr)) { return false; } } return true; } /* * Waits for all peers to receive the mod event. */ static void check_mod_event(AutoTox *autotoxes, size_t num_peers, Tox_Group_Mod_Event event) { uint32_t peers_recv_changes = 0; do { peers_recv_changes = 0; iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); for (size_t i = 0; i < num_peers; ++i) { State *state = (State *)autotoxes[i].state; bool check = false; switch (event) { case TOX_GROUP_MOD_EVENT_MODERATOR: { if (state->mod_check) { check = true; state->mod_check = false; } break; } case TOX_GROUP_MOD_EVENT_OBSERVER: { if (state->observer_check) { check = true; state->observer_check = false; } break; } case TOX_GROUP_MOD_EVENT_USER: { if (state->user_check) { check = true; state->user_check = false; } break; } case TOX_GROUP_MOD_EVENT_KICK: { check = state->kick_check; break; } default: { ck_assert(0); } } if (check) { ++peers_recv_changes; } } } while (peers_recv_changes < num_peers - 1); } static uint32_t get_peer_id_by_nick(const Peer *peers, uint32_t num_peers, const char *name) { ck_assert(name != nullptr); for (uint32_t i = 0; i < num_peers; ++i) { if (memcmp(peers[i].name, name, peers[i].name_length) == 0) { return peers[i].peer_id; } } ck_assert_msg(0, "Failed to find peer id"); } static size_t get_state_index_by_nick(const AutoTox *autotoxes, size_t num_peers, const char *name, size_t name_length) { ck_assert(name != nullptr && name_length <= TOX_MAX_NAME_LENGTH); for (size_t i = 0; i < num_peers; ++i) { const State *state = (const State *)autotoxes[i].state; if (memcmp(state->self_name, name, name_length) == 0) { return i; } } ck_assert_msg(0, "Failed to find index"); } static void group_join_fail_handler(const Tox_Event_Group_Join_Fail *event, void *user_data) { const Tox_Group_Join_Fail fail_type = tox_event_group_join_fail_get_fail_type(event); fprintf(stderr, "Failed to join group: %d", fail_type); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t group_number = tox_event_group_peer_join_get_group_number(event); const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); ck_assert(state->group_number == group_number); char peer_name[TOX_MAX_NAME_LENGTH + 1]; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, group_number, peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); tox_group_peer_get_name(autotox->tox, group_number, peer_id, (uint8_t *) peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); Peer *peer = &state->peers[state->num_peers]; peer->peer_id = peer_id; memcpy(peer->name, peer_name, peer_name_len); peer->name_length = peer_name_len; ++state->num_peers; ck_assert(state->num_peers < NUM_GROUP_TOXES); } static void handle_mod(State *state, const char *peer_name, size_t peer_name_len) { if (state->mod_event_count == 0) { ck_assert(memcmp(peer_name, state->mod_name1, peer_name_len) == 0); } else if (state->mod_event_count == 1) { ck_assert(memcmp(peer_name, state->mod_name2, peer_name_len) == 0); } else { ck_assert(false); } ++state->mod_event_count; state->mod_check = true; } static void handle_observer(State *state, const char *peer_name, size_t peer_name_len) { if (state->observer_event_count == 0) { ck_assert(memcmp(peer_name, state->observer_name1, peer_name_len) == 0); } else if (state->observer_event_count == 1) { ck_assert(memcmp(peer_name, state->observer_name2, peer_name_len) == 0); } else { ck_assert(false); } ++state->observer_event_count; state->observer_check = true; } static void handle_user(State *state, const char *peer_name, size_t peer_name_len) { // event 1: observer1 gets promoted back to user // event 2: observer2 gets promoted to moderator // event 3: moderator 1 gets kicked // event 4: moderator 2 gets demoted to moderator if (state->user_event_count == 0) { ck_assert(memcmp(peer_name, state->observer_name1, peer_name_len) == 0); } else if (state->user_event_count == 1) { ck_assert(memcmp(peer_name, state->observer_name2, peer_name_len) == 0); } else if (state->user_event_count == 2) { ck_assert(memcmp(peer_name, state->mod_name1, peer_name_len) == 0); } else if (state->user_event_count == 3) { ck_assert(memcmp(peer_name, state->mod_name2, peer_name_len) == 0); } else { ck_assert(false); } ++state->user_event_count; state->user_check = true; } static void group_mod_event_handler(const Tox_Event_Group_Moderation *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t group_number = tox_event_group_moderation_get_group_number(event); const uint32_t target_peer_id = tox_event_group_moderation_get_target_peer_id(event); const Tox_Group_Mod_Event mod_type = tox_event_group_moderation_get_mod_type(event); ck_assert(state->group_number == group_number); char peer_name[TOX_MAX_NAME_LENGTH + 1]; Tox_Err_Group_Peer_Query q_err; size_t peer_name_len = tox_group_peer_get_name_size(autotox->tox, group_number, target_peer_id, &q_err); if (q_err == TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND) { // may occurr on sync attempts return; } ck_assert_msg(q_err == TOX_ERR_GROUP_PEER_QUERY_OK, "error %d", q_err); ck_assert(peer_name_len <= TOX_MAX_NAME_LENGTH); tox_group_peer_get_name(autotox->tox, group_number, target_peer_id, (uint8_t *) peer_name, &q_err); peer_name[peer_name_len] = 0; ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); Tox_Group_Role role = tox_group_peer_get_role(autotox->tox, group_number, target_peer_id, &q_err); ck_assert(q_err == TOX_ERR_GROUP_PEER_QUERY_OK); ck_assert(role <= TOX_GROUP_ROLE_OBSERVER); fprintf(stderr, "tox%u: got moderator event %d (%s), role = %s\n", autotox->index, mod_type, tox_group_mod_event_to_string(mod_type), tox_group_role_to_string(role)); switch (mod_type) { case TOX_GROUP_MOD_EVENT_MODERATOR: { handle_mod(state, peer_name, peer_name_len); break; } case TOX_GROUP_MOD_EVENT_OBSERVER: { handle_observer(state, peer_name, peer_name_len); break; } case TOX_GROUP_MOD_EVENT_USER: { handle_user(state, peer_name, peer_name_len); break; } case TOX_GROUP_MOD_EVENT_KICK: { ck_assert(memcmp(peer_name, state->mod_name1, peer_name_len) == 0); state->kick_check = true; break; } default: { ck_assert_msg(0, "Got invalid moderator event %d", mod_type); return; } } } /* Checks that `peer_id` sees itself with the role `role`. */ static void check_self_role(AutoTox *autotoxes, uint32_t peer_id, Tox_Group_Role role) { Tox_Err_Group_Self_Query sq_err; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; uint32_t self_peer_id = tox_group_self_get_peer_id(autotoxes[i].tox, state->group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (self_peer_id == peer_id) { Tox_Group_Role self_role = tox_group_self_get_role(autotoxes[i].tox, state->group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_role == role); return; } } } /* Makes sure that a peer's role respects the voice state */ static void voice_state_message_test(AutoTox *autotox, Tox_Group_Voice_State voice_state) { const State *state = (State *)autotox->state; Tox_Err_Group_Self_Query sq_err; Tox_Group_Role self_role = tox_group_self_get_role(autotox->tox, state->group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_Err_Group_Send_Message msg_err; tox_group_send_message(autotox->tox, state->group_number, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)"test", 4, &msg_err); switch (self_role) { case TOX_GROUP_ROLE_OBSERVER: { ck_assert(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS); break; } case TOX_GROUP_ROLE_USER: { if (voice_state != TOX_GROUP_VOICE_STATE_ALL) { ck_assert_msg(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS, "%d", msg_err); } else { ck_assert(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_OK); } break; } case TOX_GROUP_ROLE_MODERATOR: { if (voice_state != TOX_GROUP_VOICE_STATE_FOUNDER) { ck_assert(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_OK); } else { ck_assert(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS); } break; } case TOX_GROUP_ROLE_FOUNDER: { ck_assert(msg_err == TOX_ERR_GROUP_SEND_MESSAGE_OK); break; } } } static bool all_peers_got_voice_state_change(AutoTox *autotoxes, uint32_t num_toxes, Tox_Group_Voice_State expected_voice_state) { Tox_Err_Group_State_Query query_err; for (uint32_t i = 0; i < num_toxes; ++i) { const State *state = (State *)autotoxes[i].state; Tox_Group_Voice_State voice_state = tox_group_get_voice_state(autotoxes[i].tox, state->group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (voice_state != expected_voice_state) { return false; } } return true; } static void check_voice_state(AutoTox *autotoxes, uint32_t num_toxes) { // founder sets voice state to Moderator const State *state = (State *)autotoxes[0].state; Tox_Err_Group_Set_Voice_State voice_set_err; tox_group_set_voice_state(autotoxes[0].tox, state->group_number, TOX_GROUP_VOICE_STATE_MODERATOR, &voice_set_err); ck_assert(voice_set_err == TOX_ERR_GROUP_SET_VOICE_STATE_OK); for (uint32_t i = 0; i < num_toxes; ++i) { do { iterate_all_wait(autotoxes, num_toxes, ITERATION_INTERVAL); } while (!all_peers_got_voice_state_change(autotoxes, num_toxes, TOX_GROUP_VOICE_STATE_MODERATOR)); voice_state_message_test(&autotoxes[i], TOX_GROUP_VOICE_STATE_MODERATOR); } tox_group_set_voice_state(autotoxes[0].tox, state->group_number, TOX_GROUP_VOICE_STATE_FOUNDER, &voice_set_err); ck_assert(voice_set_err == TOX_ERR_GROUP_SET_VOICE_STATE_OK); for (uint32_t i = 0; i < num_toxes; ++i) { do { iterate_all_wait(autotoxes, num_toxes, ITERATION_INTERVAL); } while (!all_peers_got_voice_state_change(autotoxes, num_toxes, TOX_GROUP_VOICE_STATE_FOUNDER)); voice_state_message_test(&autotoxes[i], TOX_GROUP_VOICE_STATE_FOUNDER); } tox_group_set_voice_state(autotoxes[0].tox, state->group_number, TOX_GROUP_VOICE_STATE_ALL, &voice_set_err); ck_assert(voice_set_err == TOX_ERR_GROUP_SET_VOICE_STATE_OK); for (uint32_t i = 0; i < num_toxes; ++i) { do { iterate_all_wait(autotoxes, num_toxes, ITERATION_INTERVAL); } while (!all_peers_got_voice_state_change(autotoxes, num_toxes, TOX_GROUP_VOICE_STATE_ALL)); voice_state_message_test(&autotoxes[i], TOX_GROUP_VOICE_STATE_ALL); } } static void group_moderation_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES >= 4, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); ck_assert_msg(NUM_GROUP_TOXES < 10, "NUM_GROUP_TOXES is too big: %d", NUM_GROUP_TOXES); uint16_t name_length = 6; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { State *state = (State *)autotoxes[i].state; state->self_name_length = name_length; snprintf(state->self_name, sizeof(state->self_name), "peer_%zu", i); state->self_name[name_length] = 0; tox_events_callback_group_join_fail(autotoxes[i].dispatch, group_join_fail_handler); tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); tox_events_callback_group_moderation(autotoxes[i].dispatch, group_mod_event_handler); } iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); fprintf(stderr, "Creating new group\n"); /* Founder makes new group */ State *state0 = (State *)autotoxes[0].state; Tox *tox0 = autotoxes[0].tox; Tox_Err_Group_New err_new; state0->group_number = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)state0->self_name, state0->self_name_length, &err_new); ck_assert_msg(err_new == TOX_ERR_GROUP_NEW_OK, "Failed to create group. error: %d\n", err_new); /* Founder gets chat ID */ Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, state0->group_number, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get chat ID. error: %d", id_err); fprintf(stderr, "Peers attemping to join DHT group via the chat ID\n"); for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); State *state = (State *)autotoxes[i].state; Tox_Err_Group_Join join_err; state->group_number = tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)state->self_name, state->self_name_length, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "Peer %s (%zu) failed to join group. error %d", state->self_name, i, join_err); c_sleep(100); } // make sure every peer sees every other peer before we continue do { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_peers_connected(autotoxes)); /* manually tell the other peers the names of the peers that will be assigned new roles */ for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { State *state = (State *)autotoxes[i].state; memcpy(state->mod_name1, state0->peers[0].name, sizeof(state->mod_name1)); memcpy(state->mod_name2, state0->peers[2].name, sizeof(state->mod_name2)); memcpy(state->observer_name1, state0->peers[1].name, sizeof(state->observer_name1)); memcpy(state->observer_name2, state0->peers[2].name, sizeof(state->observer_name2)); } /* founder checks his own role */ Tox_Err_Group_Self_Query sq_err; Tox_Group_Role self_role = tox_group_self_get_role(tox0, state0->group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_role == TOX_GROUP_ROLE_FOUNDER); /* all peers should be user role except founder */ for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; self_role = tox_group_self_get_role(autotoxes[i].tox, state->group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); ck_assert(self_role == TOX_GROUP_ROLE_USER); } /* founder sets first peer to moderator */ fprintf(stderr, "Founder setting %s to moderator\n", state0->peers[0].name); Tox_Err_Group_Set_Role role_err; tox_group_set_role(tox0, state0->group_number, state0->peers[0].peer_id, TOX_GROUP_ROLE_MODERATOR, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set moderator. error: %d", role_err); // manually flag the role setter because they don't get a callback state0->mod_check = true; ++state0->mod_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_MODERATOR); check_self_role(autotoxes, state0->peers[0].peer_id, TOX_GROUP_ROLE_MODERATOR); fprintf(stderr, "All peers successfully received mod event\n"); /* founder sets second and third peer to observer */ fprintf(stderr, "Founder setting %s to observer\n", state0->peers[1].name); tox_group_set_role(tox0, state0->group_number, state0->peers[1].peer_id, TOX_GROUP_ROLE_OBSERVER, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set observer. error: %d", role_err); state0->observer_check = true; ++state0->observer_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_OBSERVER); fprintf(stderr, "All peers successfully received observer event 1\n"); fprintf(stderr, "Founder setting %s to observer\n", state0->peers[2].name); tox_group_set_role(tox0, state0->group_number, state0->peers[2].peer_id, TOX_GROUP_ROLE_OBSERVER, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set observer. error: %d", role_err); state0->observer_check = true; ++state0->observer_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_OBSERVER); check_self_role(autotoxes, state0->peers[1].peer_id, TOX_GROUP_ROLE_OBSERVER); fprintf(stderr, "All peers successfully received observer event 2\n"); /* do voice state test here since we have at least one peer of each role */ check_voice_state(autotoxes, NUM_GROUP_TOXES); fprintf(stderr, "Voice state respected by all peers\n"); /* New moderator promotes second peer back to user */ const uint32_t idx = get_state_index_by_nick(autotoxes, NUM_GROUP_TOXES, state0->peers[0].name, state0->peers[0].name_length); State *state1 = (State *)autotoxes[idx].state; Tox *tox1 = autotoxes[idx].tox; const uint32_t obs_peer_id = get_peer_id_by_nick(state1->peers, NUM_GROUP_TOXES - 1, state1->observer_name1); fprintf(stderr, "%s is promoting %s back to user\n", state1->self_name, state0->peers[1].name); tox_group_set_role(tox1, state1->group_number, obs_peer_id, TOX_GROUP_ROLE_USER, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to promote observer back to user. error: %d", role_err); state1->user_check = true; ++state1->user_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_USER); fprintf(stderr, "All peers successfully received user event\n"); /* founder assigns third peer to moderator (this triggers two events: user and moderator) */ fprintf(stderr, "Founder setting %s to moderator\n", state0->peers[2].name); tox_group_set_role(tox0, state0->group_number, state0->peers[2].peer_id, TOX_GROUP_ROLE_MODERATOR, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set moderator. error: %d", role_err); state0->mod_check = true; ++state0->mod_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_MODERATOR); check_self_role(autotoxes, state0->peers[2].peer_id, TOX_GROUP_ROLE_MODERATOR); fprintf(stderr, "All peers successfully received moderator event\n"); /* moderator attempts to demote and kick founder */ uint32_t founder_peer_id = get_peer_id_by_nick(state1->peers, NUM_GROUP_TOXES - 1, state0->self_name); tox_group_set_role(tox1, state1->group_number, founder_peer_id, TOX_GROUP_ROLE_OBSERVER, &role_err); ck_assert_msg(role_err != TOX_ERR_GROUP_SET_ROLE_OK, "Mod set founder to observer"); Tox_Err_Group_Kick_Peer k_err; tox_group_kick_peer(tox1, state1->group_number, founder_peer_id, &k_err); ck_assert_msg(k_err != TOX_ERR_GROUP_KICK_PEER_OK, "Mod kicked founder"); /* the moderator about to be kicked changes the topic to trigger the founder to * re-sign and redistribute it after the kick. */ const State *state_x = (const State *)autotoxes[idx].state; Tox *tox_x = autotoxes[idx].tox; Tox_Err_Group_Topic_Set topic_err; tox_group_set_topic(tox_x, state_x->group_number, nullptr, 0, &topic_err); ck_assert(topic_err == TOX_ERR_GROUP_TOPIC_SET_OK); /* founder kicks moderator (this triggers two events: user and kick) */ fprintf(stderr, "Founder is kicking %s\n", state0->peers[0].name); tox_group_kick_peer(tox0, state0->group_number, state0->peers[0].peer_id, &k_err); ck_assert_msg(k_err == TOX_ERR_GROUP_KICK_PEER_OK, "Failed to kick peer. error: %d", k_err); state0->kick_check = true; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_KICK); fprintf(stderr, "All peers successfully received kick event\n"); fprintf(stderr, "Founder is demoting moderator to user\n"); tox_group_set_role(tox0, state0->group_number, state0->peers[2].peer_id, TOX_GROUP_ROLE_USER, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to demote peer 3 to User. error: %d", role_err); state0->user_check = true; ++state0->user_event_count; check_mod_event(autotoxes, NUM_GROUP_TOXES, TOX_GROUP_MOD_EVENT_USER); check_self_role(autotoxes, state0->peers[2].peer_id, TOX_GROUP_ROLE_USER); for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { const State *state = (const State *)autotoxes[i].state; Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[i].tox, state->group_number, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); } fprintf(stderr, "All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_moderation_test, sizeof(State), &options); return 0; } #undef NUM_GROUP_TOXES #undef GROUP_NAME #undef GROUP_NAME_LEN c-toxcore-0.2.20/auto_tests/group_save_test.c0000644060175106017510000002356314714247532017257 0ustar robin/* * Tests that we can save a groupchat and load a groupchat with the saved data. */ #include #include #include #include #include "auto_test_support.h" typedef struct State { bool peer_joined; } State; #define NUM_GROUP_TOXES 2 #define GROUP_NAME "The Test Chamber" #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) #define TOPIC "They're waiting for you Gordon..." #define TOPIC_LEN (sizeof(TOPIC) - 1) #define NEW_PRIV_STATE TOX_GROUP_PRIVACY_STATE_PRIVATE #define PASSWORD "password123" #define PASS_LEN (sizeof(PASSWORD) - 1) #define PEER_LIMIT 69 #define PEER0_NICK "Mike" #define PEER0_NICK_LEN (sizeof(PEER0_NICK) -1) #define NEW_USER_STATUS TOX_USER_STATUS_BUSY static void group_invite_handler(const Tox_Event_Group_Invite *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t friend_number = tox_event_group_invite_get_friend_number(event); const uint8_t *invite_data = tox_event_group_invite_get_invite_data(event); const size_t length = tox_event_group_invite_get_invite_data_length(event); Tox_Err_Group_Invite_Accept err_accept; tox_group_invite_accept(autotox->tox, friend_number, invite_data, length, (const uint8_t *)"test2", 5, nullptr, 0, &err_accept); ck_assert(err_accept == TOX_ERR_GROUP_INVITE_ACCEPT_OK); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; state->peer_joined = true; } /* Checks that group has the same state according to the above defines * * Returns 0 if state is correct. * Returns a value < 0 if state is incorrect. */ static int has_correct_group_state(const Tox *tox, uint32_t group_number, const uint8_t *expected_chat_id) { Tox_Err_Group_State_Query query_err; Tox_Group_Privacy_State priv_state = tox_group_get_privacy_state(tox, group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (priv_state != NEW_PRIV_STATE) { return -1; } size_t pass_len = tox_group_get_password_size(tox, group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); uint8_t password[TOX_GROUP_MAX_PASSWORD_SIZE]; tox_group_get_password(tox, group_number, password, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (pass_len != PASS_LEN || memcmp(password, PASSWORD, pass_len) != 0) { return -2; } size_t gname_len = tox_group_get_name_size(tox, group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); uint8_t group_name[TOX_GROUP_MAX_GROUP_NAME_LENGTH]; tox_group_get_name(tox, group_number, group_name, &query_err); if (gname_len != GROUP_NAME_LEN || memcmp(group_name, GROUP_NAME, gname_len) != 0) { return -3; } if (tox_group_get_peer_limit(tox, group_number, nullptr) != PEER_LIMIT) { return -4; } Tox_Group_Topic_Lock topic_lock = tox_group_get_topic_lock(tox, group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (topic_lock != TOX_GROUP_TOPIC_LOCK_DISABLED) { return -5; } Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox, group_number, chat_id, &id_err); ck_assert(id_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (memcmp(chat_id, expected_chat_id, TOX_GROUP_CHAT_ID_SIZE) != 0) { return -6; } return 0; } static int has_correct_self_state(const Tox *tox, uint32_t group_number, const uint8_t *expected_self_pk) { Tox_Err_Group_Self_Query sq_err; size_t self_length = tox_group_self_get_name_size(tox, group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); uint8_t self_name[TOX_MAX_NAME_LENGTH]; tox_group_self_get_name(tox, group_number, self_name, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (self_length != PEER0_NICK_LEN || memcmp(self_name, PEER0_NICK, self_length) != 0) { return -1; } Tox_User_Status self_status = tox_group_self_get_status(tox, group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (self_status != NEW_USER_STATUS) { return -2; } Tox_Group_Role self_role = tox_group_self_get_role(tox, group_number, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (self_role != TOX_GROUP_ROLE_FOUNDER) { return -3; } uint8_t self_pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; tox_group_self_get_public_key(tox, group_number, self_pk, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); if (memcmp(self_pk, expected_self_pk, TOX_GROUP_PEER_PUBLIC_KEY_SIZE) != 0) { return -4; } return 0; } static void group_save_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES > 1, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_invite(autotoxes[i].dispatch, group_invite_handler); tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); } Tox *tox0 = autotoxes[0].tox; const State *state0 = (State *)autotoxes[0].state; const State *state1 = (State *)autotoxes[1].state; Tox_Err_Group_New err_new; const uint32_t group_number = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PRIVATE, (const uint8_t *)GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)"test", 4, &err_new); ck_assert(err_new == TOX_ERR_GROUP_NEW_OK); uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; Tox_Err_Group_State_Query id_err; tox_group_get_chat_id(tox0, group_number, chat_id, &id_err); ck_assert(id_err == TOX_ERR_GROUP_STATE_QUERY_OK); uint8_t founder_pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; Tox_Err_Group_Self_Query sq_err; tox_group_self_get_public_key(tox0, group_number, founder_pk, &sq_err); ck_assert(sq_err == TOX_ERR_GROUP_SELF_QUERY_OK); Tox_Err_Group_Invite_Friend err_invite; tox_group_invite_friend(tox0, group_number, 0, &err_invite); ck_assert(err_invite == TOX_ERR_GROUP_INVITE_FRIEND_OK); while (!state0->peer_joined && !state1->peer_joined) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } printf("tox0 invites tox1 to group\n"); // change group state Tox_Err_Group_Topic_Set top_err; tox_group_set_topic(tox0, group_number, (const uint8_t *)TOPIC, TOPIC_LEN, &top_err); ck_assert(top_err == TOX_ERR_GROUP_TOPIC_SET_OK); Tox_Err_Group_Set_Topic_Lock lock_set_err; tox_group_set_topic_lock(tox0, group_number, TOX_GROUP_TOPIC_LOCK_DISABLED, &lock_set_err); ck_assert(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK); Tox_Err_Group_Set_Privacy_State priv_err; tox_group_set_privacy_state(tox0, group_number, NEW_PRIV_STATE, &priv_err); ck_assert(priv_err == TOX_ERR_GROUP_SET_PRIVACY_STATE_OK); Tox_Err_Group_Set_Password pass_set_err; tox_group_set_password(tox0, group_number, (const uint8_t *)PASSWORD, PASS_LEN, &pass_set_err); ck_assert(pass_set_err == TOX_ERR_GROUP_SET_PASSWORD_OK); Tox_Err_Group_Set_Peer_Limit limit_set_err; tox_group_set_peer_limit(tox0, group_number, PEER_LIMIT, &limit_set_err); ck_assert(limit_set_err == TOX_ERR_GROUP_SET_PEER_LIMIT_OK); // change self state Tox_Err_Group_Self_Name_Set n_err; tox_group_self_set_name(tox0, group_number, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, &n_err); ck_assert(n_err == TOX_ERR_GROUP_SELF_NAME_SET_OK); Tox_Err_Group_Self_Status_Set s_err; tox_group_self_set_status(tox0, group_number, NEW_USER_STATUS, &s_err); ck_assert(s_err == TOX_ERR_GROUP_SELF_STATUS_SET_OK); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); printf("tox0 changes group state\n"); const size_t save_length = tox_get_savedata_size(tox0); uint8_t *save = (uint8_t *)malloc(save_length); ck_assert(save != nullptr); tox_get_savedata(tox0, save); for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { tox_group_leave(autotoxes[i].tox, group_number, nullptr, 0, nullptr); } struct Tox_Options *const options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, save, save_length); tox_options_set_experimental_groups_persistence(options, true); Tox *new_tox = tox_new_log(options, nullptr, nullptr); ck_assert(new_tox != nullptr); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); printf("tox0 saves group and reloads client\n"); const int group_ret = has_correct_group_state(new_tox, group_number, chat_id); ck_assert_msg(group_ret == 0, "incorrect group state: %d", group_ret); const int self_ret = has_correct_self_state(new_tox, group_number, founder_pk); ck_assert_msg(self_ret == 0, "incorrect self state: %d", self_ret); tox_group_leave(new_tox, group_number, nullptr, 0, nullptr); free(save); tox_options_free(options); tox_kill(new_tox); printf("All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; Tox_Options *opts = tox_options_new(nullptr); ck_assert(opts != nullptr); tox_options_set_experimental_groups_persistence(opts, true); run_auto_test(opts, NUM_GROUP_TOXES, group_save_test, sizeof(State), &autotest_opts); tox_options_free(opts); return 0; } #undef NUM_GROUP_TOXES #undef GROUP_NAME #undef GROUP_NAME_LEN #undef TOPIC #undef TOPIC_LEN #undef NEW_PRIV_STATE #undef PASSWORD #undef PASS_LEN #undef PEER_LIMIT #undef PEER0_NICK #undef PEER0_NICK_LEN #undef NEW_USER_STATUS c-toxcore-0.2.20/auto_tests/group_state_test.c0000644060175106017510000003446114714247532017440 0ustar robin/* * Tests that we can successfully change the group state and that all peers in the group * receive the correct state changes. */ #include #include #include #include #include #include "auto_test_support.h" #include "check_compat.h" #define NUM_GROUP_TOXES 5 #define PEER_LIMIT_1 NUM_GROUP_TOXES #define PEER_LIMIT_2 50 #define PASSWORD "dadada" #define PASS_LEN (sizeof(PASSWORD) - 1) #define GROUP_NAME "The Crystal Palace" #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) #define PEER0_NICK "David" #define PEER0_NICK_LEN (sizeof(PEER0_NICK) - 1) typedef struct State { size_t num_peers; } State; static bool all_group_peers_connected(const AutoTox *autotoxes, uint32_t tox_count, uint32_t groupnumber, size_t name_length, uint32_t peer_limit) { for (uint32_t i = 0; i < tox_count; ++i) { // make sure we got an invite response if (tox_group_get_name_size(autotoxes[i].tox, groupnumber, nullptr) != name_length) { return false; } // make sure we got a sync response if (tox_group_get_peer_limit(autotoxes[i].tox, groupnumber, nullptr) != peer_limit) { return false; } // make sure we're actually connected if (!tox_group_is_connected(autotoxes[i].tox, groupnumber, nullptr)) { return false; } const State *state = (const State *)autotoxes[i].state; // make sure all peers are connected to one another if (state->num_peers < NUM_GROUP_TOXES - 1) { return false; } } return true; } static void group_topic_lock_handler(const Tox_Event_Group_Topic_Lock *event, void *user_data) { const AutoTox *autotox = (const AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_topic_lock_get_group_number(event); const Tox_Group_Topic_Lock topic_lock = tox_event_group_topic_lock_get_topic_lock(event); Tox_Err_Group_State_Query err; Tox_Group_Topic_Lock current_topic_lock = tox_group_get_topic_lock(autotox->tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(current_topic_lock == topic_lock, "topic locks don't match in callback: %d %d", topic_lock, current_topic_lock); } static void group_voice_state_handler(const Tox_Event_Group_Voice_State *event, void *user_data) { const AutoTox *autotox = (const AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_voice_state_get_group_number(event); const Tox_Group_Voice_State voice_state = tox_event_group_voice_state_get_voice_state(event); Tox_Err_Group_State_Query err; Tox_Group_Voice_State current_voice_state = tox_group_get_voice_state(autotox->tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(current_voice_state == voice_state, "voice states don't match in callback: %d %d", voice_state, current_voice_state); } static void group_privacy_state_handler(const Tox_Event_Group_Privacy_State *event, void *user_data) { const AutoTox *autotox = (const AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_privacy_state_get_group_number(event); const Tox_Group_Privacy_State privacy_state = tox_event_group_privacy_state_get_privacy_state(event); Tox_Err_Group_State_Query err; Tox_Group_Privacy_State current_pstate = tox_group_get_privacy_state(autotox->tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(current_pstate == privacy_state, "privacy states don't match in callback"); } static void group_peer_limit_handler(const Tox_Event_Group_Peer_Limit *event, void *user_data) { const AutoTox *autotox = (const AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_peer_limit_get_group_number(event); const uint32_t peer_limit = tox_event_group_peer_limit_get_peer_limit(event); Tox_Err_Group_State_Query err; uint32_t current_plimit = tox_group_get_peer_limit(autotox->tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(peer_limit == current_plimit, "Peer limits don't match in callback: %u, %u\n", peer_limit, current_plimit); } static void group_password_handler(const Tox_Event_Group_Password *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t groupnumber = tox_event_group_password_get_group_number(event); const uint8_t *password = tox_event_group_password_get_password(event); const size_t length = tox_event_group_password_get_password_length(event); Tox_Err_Group_State_Query err; size_t curr_pwlength = tox_group_get_password_size(autotox->tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert(length == curr_pwlength); uint8_t current_password[TOX_GROUP_MAX_PASSWORD_SIZE]; tox_group_get_password(autotox->tox, groupnumber, current_password, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(memcmp(current_password, password, length) == 0, "Passwords don't match: %s, %s", password, current_password); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ++state->num_peers; ck_assert(state->num_peers < NUM_GROUP_TOXES); } /* Returns 0 if group state is equal to the state passed to this function. * Returns negative integer if state is invalid. */ static int check_group_state(const Tox *tox, uint32_t groupnumber, uint32_t peer_limit, Tox_Group_Privacy_State priv_state, Tox_Group_Voice_State voice_state, const uint8_t *password, size_t pass_len, Tox_Group_Topic_Lock topic_lock) { Tox_Err_Group_State_Query query_err; Tox_Group_Privacy_State my_priv_state = tox_group_get_privacy_state(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get privacy state: %d", query_err); if (my_priv_state != priv_state) { return -1; } uint32_t my_peer_limit = tox_group_get_peer_limit(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get peer limit: %d", query_err); if (my_peer_limit != peer_limit) { return -2; } size_t my_pass_len = tox_group_get_password_size(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get password size: %d", query_err); if (my_pass_len != pass_len) { return -5; } if (password != nullptr && my_pass_len > 0) { ck_assert(my_pass_len <= TOX_GROUP_MAX_PASSWORD_SIZE); uint8_t my_pass[TOX_GROUP_MAX_PASSWORD_SIZE + 1]; tox_group_get_password(tox, groupnumber, my_pass, &query_err); my_pass[my_pass_len] = 0; ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get password: %d", query_err); if (memcmp(my_pass, password, my_pass_len) != 0) { return -6; } } /* Group name should never change */ size_t my_gname_len = tox_group_get_name_size(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get group name size: %d", query_err); if (my_gname_len != GROUP_NAME_LEN) { return -7; } ck_assert(my_gname_len <= TOX_GROUP_MAX_GROUP_NAME_LENGTH); uint8_t my_gname[TOX_GROUP_MAX_GROUP_NAME_LENGTH + 1]; tox_group_get_name(tox, groupnumber, my_gname, &query_err); my_gname[my_gname_len] = 0; if (memcmp(my_gname, (const uint8_t *)GROUP_NAME, my_gname_len) != 0) { return -8; } Tox_Group_Topic_Lock current_topic_lock = tox_group_get_topic_lock(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get topic lock: %d", query_err); if (current_topic_lock != topic_lock) { return -9; } Tox_Group_Voice_State current_voice_state = tox_group_get_voice_state(tox, groupnumber, &query_err); ck_assert_msg(query_err == TOX_ERR_GROUP_STATE_QUERY_OK, "Failed to get voice state: %d", query_err); if (current_voice_state != voice_state) { return -10; } return 0; } static void set_group_state(Tox *tox, uint32_t groupnumber, uint32_t peer_limit, Tox_Group_Privacy_State priv_state, Tox_Group_Voice_State voice_state, const uint8_t *password, size_t pass_len, Tox_Group_Topic_Lock topic_lock) { Tox_Err_Group_Set_Peer_Limit limit_set_err; tox_group_set_peer_limit(tox, groupnumber, peer_limit, &limit_set_err); ck_assert_msg(limit_set_err == TOX_ERR_GROUP_SET_PEER_LIMIT_OK, "failed to set peer limit: %d", limit_set_err); Tox_Err_Group_Set_Privacy_State priv_err; tox_group_set_privacy_state(tox, groupnumber, priv_state, &priv_err); ck_assert_msg(priv_err == TOX_ERR_GROUP_SET_PRIVACY_STATE_OK, "failed to set privacy state: %d", priv_err); Tox_Err_Group_Set_Password pass_set_err; tox_group_set_password(tox, groupnumber, password, pass_len, &pass_set_err); ck_assert_msg(pass_set_err == TOX_ERR_GROUP_SET_PASSWORD_OK, "failed to set password: %d", pass_set_err); Tox_Err_Group_Set_Topic_Lock lock_set_err; tox_group_set_topic_lock(tox, groupnumber, topic_lock, &lock_set_err); ck_assert_msg(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK, "failed to set topic lock: %d", lock_set_err); Tox_Err_Group_Set_Voice_State voice_set_err; tox_group_set_voice_state(tox, groupnumber, voice_state, &voice_set_err); ck_assert_msg(voice_set_err == TOX_ERR_GROUP_SET_VOICE_STATE_OK, "failed to set voice state: %d", voice_set_err); } static void group_state_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES >= 3, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_privacy_state(autotoxes[i].dispatch, group_privacy_state_handler); tox_events_callback_group_peer_limit(autotoxes[i].dispatch, group_peer_limit_handler); tox_events_callback_group_password(autotoxes[i].dispatch, group_password_handler); tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); tox_events_callback_group_voice_state(autotoxes[i].dispatch, group_voice_state_handler); tox_events_callback_group_topic_lock(autotoxes[i].dispatch, group_topic_lock_handler); } Tox *tox0 = autotoxes[0].tox; /* Tox 0 creates a group and is the founder of a newly created group */ Tox_Err_Group_New new_err; uint32_t groupnum = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, &new_err); ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err); /* Founder sets default group state before anyone else joins */ set_group_state(tox0, groupnum, PEER_LIMIT_1, TOX_GROUP_PRIVACY_STATE_PUBLIC, TOX_GROUP_VOICE_STATE_ALL, (const uint8_t *)PASSWORD, PASS_LEN, TOX_GROUP_TOPIC_LOCK_ENABLED); /* Founder gets the Chat ID and implicitly shares it publicly */ Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, groupnum, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "tox_group_get_chat_id failed %d", id_err); /* All other peers join the group using the Chat ID and password */ for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); Tox_Err_Group_Join join_err; tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, (const uint8_t *)PASSWORD, PASS_LEN, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "tox_group_join failed: %d", join_err); } fprintf(stderr, "Peers attempting to join group\n"); /* Keep checking if all instances have connected to the group until test times out */ while (!all_group_peers_connected(autotoxes, NUM_GROUP_TOXES, groupnum, GROUP_NAME_LEN, PEER_LIMIT_1)) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } /* Change group state and check that all peers received the changes */ set_group_state(tox0, groupnum, PEER_LIMIT_2, TOX_GROUP_PRIVACY_STATE_PRIVATE, TOX_GROUP_VOICE_STATE_MODERATOR, nullptr, 0, TOX_GROUP_TOPIC_LOCK_DISABLED); fprintf(stderr, "Changing state\n"); while (1) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); uint32_t count = 0; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { if (check_group_state(autotoxes[i].tox, groupnum, PEER_LIMIT_2, TOX_GROUP_PRIVACY_STATE_PRIVATE, TOX_GROUP_VOICE_STATE_MODERATOR, nullptr, 0, TOX_GROUP_TOPIC_LOCK_DISABLED) == 0) { ++count; } } if (count == NUM_GROUP_TOXES) { fprintf(stderr, "%u peers successfully received state changes\n", count); break; } } for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[i].tox, groupnum, nullptr, 0, &err_exit); ck_assert_msg(err_exit == TOX_ERR_GROUP_LEAVE_OK, "%d", err_exit); } fprintf(stderr, "All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_state_test, sizeof(State), &autotest_opts); return 0; } #undef PEER0_NICK #undef PEER0_NICK_LEN #undef GROUP_NAME_LEN #undef GROUP_NAME #undef PASS_LEN #undef PASSWORD #undef PEER_LIMIT_2 #undef PEER_LIMIT_1 #undef NUM_GROUP_TOXES c-toxcore-0.2.20/auto_tests/group_sync_test.c0000644060175106017510000003544114714247532017273 0ustar robin/* * Tests syncing capabilities of groups: we attempt to have multiple peers change the * group state in a number of ways and make sure that all peers end up with the same * resulting state after a short period. */ #include #include #include #include "auto_test_support.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" // these should be kept relatively low so integration tests don't always flake out // but they can be increased for local stress testing #define NUM_GROUP_TOXES 5 #define ROLE_SPAM_ITERATIONS 1 #define TOPIC_SPAM_ITERATIONS 1 typedef struct Peers { uint32_t num_peers; int64_t *peer_ids; } Peers; typedef struct State { uint8_t callback_topic[TOX_GROUP_MAX_TOPIC_LENGTH]; size_t topic_length; Peers *peers; } State; static int add_peer(Peers *peers, uint32_t peer_id) { const uint32_t new_idx = peers->num_peers; int64_t *tmp_list = (int64_t *)realloc(peers->peer_ids, sizeof(int64_t) * (peers->num_peers + 1)); if (tmp_list == nullptr) { return -1; } ++peers->num_peers; tmp_list[new_idx] = (int64_t)peer_id; peers->peer_ids = tmp_list; return 0; } static int del_peer(Peers *peers, uint32_t peer_id) { bool found_peer = false; int64_t i; for (i = 0; i < peers->num_peers; ++i) { if (peers->peer_ids[i] == peer_id) { found_peer = true; break; } } if (!found_peer) { return -1; } --peers->num_peers; if (peers->num_peers == 0) { free(peers->peer_ids); peers->peer_ids = nullptr; return 0; } if (peers->num_peers != i) { peers->peer_ids[i] = peers->peer_ids[peers->num_peers]; } peers->peer_ids[peers->num_peers] = -1; int64_t *tmp_list = (int64_t *)realloc(peers->peer_ids, sizeof(int64_t) * (peers->num_peers)); if (tmp_list == nullptr) { return -1; } peers->peer_ids = tmp_list; return 0; } static void peers_cleanup(Peers *peers) { free(peers->peer_ids); free(peers); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); ck_assert(add_peer(state->peers, peer_id) == 0); } static void group_peer_exit_handler(const Tox_Event_Group_Peer_Exit *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t peer_id = tox_event_group_peer_exit_get_peer_id(event); ck_assert(del_peer(state->peers, peer_id) == 0); } static void group_topic_handler(const Tox_Event_Group_Topic *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint8_t *topic = tox_event_group_topic_get_topic(event); const size_t length = tox_event_group_topic_get_topic_length(event); ck_assert(length <= TOX_GROUP_MAX_TOPIC_LENGTH); memcpy(state->callback_topic, (const char *)topic, length); state->topic_length = length; } static bool all_peers_connected(const AutoTox *autotoxes, uint32_t groupnumber) { for (uint32_t i = 0; i < NUM_GROUP_TOXES; ++i) { // make sure we got an invite response if (tox_group_get_name_size(autotoxes[i].tox, groupnumber, nullptr) != 4) { return false; } // make sure we're actually connected if (!tox_group_is_connected(autotoxes[i].tox, groupnumber, nullptr)) { return false; } const State *state = (const State *)autotoxes[i].state; // make sure all peers are connected to one another if (state->peers->num_peers == NUM_GROUP_TOXES - 1) { return false; } } return true; } static unsigned int get_peer_roles_checksum(const Tox *tox, const State *state, uint32_t groupnumber) { Tox_Group_Role role = tox_group_self_get_role(tox, groupnumber, nullptr); unsigned int checksum = (unsigned int)role; for (size_t i = 0; i < state->peers->num_peers; ++i) { role = tox_group_peer_get_role(tox, groupnumber, (uint32_t)state->peers->peer_ids[i], nullptr); checksum += (unsigned int)role; } return checksum; } static bool all_peers_see_same_roles(const AutoTox *autotoxes, uint32_t num_peers, uint32_t groupnumber) { const State *state0 = (const State *)autotoxes[0].state; unsigned int expected_checksum = get_peer_roles_checksum(autotoxes[0].tox, state0, groupnumber); for (size_t i = 0; i < num_peers; ++i) { const State *state = (const State *)autotoxes[i].state; unsigned int checksum = get_peer_roles_checksum(autotoxes[i].tox, state, groupnumber); if (checksum != expected_checksum) { return false; } } return true; } static void role_spam(const Random *rng, AutoTox *autotoxes, uint32_t num_peers, uint32_t num_demoted, uint32_t groupnumber) { const State *state0 = (const State *)autotoxes[0].state; Tox *tox0 = autotoxes[0].tox; for (size_t iters = 0; iters < ROLE_SPAM_ITERATIONS; ++iters) { // founder randomly promotes or demotes one of the non-mods uint32_t idx = min_u32(random_u32(rng) % num_demoted, state0->peers->num_peers); Tox_Group_Role f_role = random_u32(rng) % 2 == 0 ? TOX_GROUP_ROLE_MODERATOR : TOX_GROUP_ROLE_USER; int64_t peer_id = state0->peers->peer_ids[idx]; if (peer_id >= 0) { tox_group_set_role(tox0, groupnumber, (uint32_t)peer_id, f_role, nullptr); } // mods randomly promote or demote one of the non-mods for (uint32_t i = 1; i < num_peers; ++i) { const State *state_i = (const State *)autotoxes[i].state; for (uint32_t j = num_demoted; j < num_peers; ++j) { if (i >= state_i->peers->num_peers) { continue; } const State *state_j = (const State *)autotoxes[j].state; Tox_Group_Role role = random_u32(rng) % 2 == 0 ? TOX_GROUP_ROLE_USER : TOX_GROUP_ROLE_OBSERVER; peer_id = state_j->peers->peer_ids[i]; if (peer_id >= 0) { tox_group_set_role(autotoxes[j].tox, groupnumber, (uint32_t)peer_id, role, nullptr); } } } iterate_all_wait(autotoxes, num_peers, ITERATION_INTERVAL); } do { iterate_all_wait(autotoxes, num_peers, ITERATION_INTERVAL); } while (!all_peers_see_same_roles(autotoxes, num_peers, groupnumber)); } /* All peers attempt to set a unique topic. * * Return true if all peers successfully changed the topic. */ static bool set_topic_all_peers(const Random *rng, AutoTox *autotoxes, size_t num_peers, uint32_t groupnumber) { for (size_t i = 0; i < num_peers; ++i) { char new_topic[TOX_GROUP_MAX_TOPIC_LENGTH]; snprintf(new_topic, sizeof(new_topic), "peer %zu's topic %u", i, random_u32(rng)); const size_t length = strlen(new_topic); Tox_Err_Group_Topic_Set err; tox_group_set_topic(autotoxes[i].tox, groupnumber, (const uint8_t *)new_topic, length, &err); if (err != TOX_ERR_GROUP_TOPIC_SET_OK) { return false; } } return true; } /* Returns true if all peers have the same topic, and the topic from the get_topic API function * matches the last topic they received in the topic callback. */ static bool all_peers_have_same_topic(const AutoTox *autotoxes, uint32_t num_peers, uint32_t groupnumber) { uint8_t expected_topic[TOX_GROUP_MAX_TOPIC_LENGTH]; Tox_Err_Group_State_Query query_err; size_t expected_topic_length = tox_group_get_topic_size(autotoxes[0].tox, groupnumber, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); tox_group_get_topic(autotoxes[0].tox, groupnumber, expected_topic, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); const State *state0 = (const State *)autotoxes[0].state; if (expected_topic_length != state0->topic_length) { return false; } if (memcmp(state0->callback_topic, expected_topic, expected_topic_length) != 0) { return false; } for (size_t i = 1; i < num_peers; ++i) { size_t topic_length = tox_group_get_topic_size(autotoxes[i].tox, groupnumber, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (topic_length != expected_topic_length) { return false; } uint8_t topic[TOX_GROUP_MAX_TOPIC_LENGTH]; tox_group_get_topic(autotoxes[i].tox, groupnumber, topic, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); if (memcmp(expected_topic, (const char *)topic, topic_length) != 0) { return false; } const State *state = (const State *)autotoxes[i].state; if (topic_length != state->topic_length) { return false; } if (memcmp(state->callback_topic, (const char *)topic, topic_length) != 0) { return false; } } return true; } static void topic_spam(const Random *rng, AutoTox *autotoxes, uint32_t num_peers, uint32_t groupnumber) { for (size_t i = 0; i < TOPIC_SPAM_ITERATIONS; ++i) { do { iterate_all_wait(autotoxes, num_peers, ITERATION_INTERVAL); } while (!set_topic_all_peers(rng, autotoxes, num_peers, groupnumber)); } fprintf(stderr, "all peers set the topic at the same time\n"); do { iterate_all_wait(autotoxes, num_peers, ITERATION_INTERVAL); } while (!all_peers_have_same_topic(autotoxes, num_peers, groupnumber)); fprintf(stderr, "all peers see the same topic\n"); } static void group_sync_test(AutoTox *autotoxes) { ck_assert(NUM_GROUP_TOXES >= 5); const Random *rng = os_random(); ck_assert(rng != nullptr); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); tox_events_callback_group_topic(autotoxes[i].dispatch, group_topic_handler); tox_events_callback_group_peer_exit(autotoxes[i].dispatch, group_peer_exit_handler); State *state = (State *)autotoxes[i].state; state->peers = (Peers *)calloc(1, sizeof(Peers)); ck_assert(state->peers != nullptr); } Tox *tox0 = autotoxes[0].tox; State *state0 = (State *)autotoxes[0].state; Tox_Err_Group_New err_new; uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *) "test", 4, (const uint8_t *)"test", 4, &err_new); ck_assert(err_new == TOX_ERR_GROUP_NEW_OK); fprintf(stderr, "tox0 creats new group and invites all his friends"); Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, groupnumber, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%d", id_err); for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { Tox_Err_Group_Join join_err; tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "%d", join_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } do { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_peers_connected(autotoxes, groupnumber)); fprintf(stderr, "%d peers joined the group\n", NUM_GROUP_TOXES); Tox_Err_Group_Set_Topic_Lock lock_set_err; tox_group_set_topic_lock(tox0, groupnumber, TOX_GROUP_TOPIC_LOCK_DISABLED, &lock_set_err); ck_assert_msg(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK, "failed to disable topic lock: %d", lock_set_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); fprintf(stderr, "founder disabled topic lock; all peers try to set the topic\n"); topic_spam(rng, autotoxes, NUM_GROUP_TOXES, groupnumber); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); tox_group_set_topic_lock(tox0, groupnumber, TOX_GROUP_TOPIC_LOCK_ENABLED, &lock_set_err); ck_assert_msg(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK, "failed to enable topic lock: %d", lock_set_err); do { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_peers_have_same_topic(autotoxes, NUM_GROUP_TOXES, groupnumber) && !all_peers_see_same_roles(autotoxes, NUM_GROUP_TOXES, groupnumber) && state0->peers->num_peers != NUM_GROUP_TOXES - 1); Tox_Err_Group_Set_Role role_err; for (size_t i = 0; i < state0->peers->num_peers; ++i) { tox_group_set_role(tox0, groupnumber, (uint32_t)state0->peers->peer_ids[i], TOX_GROUP_ROLE_MODERATOR, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set moderator. error: %d", role_err); } fprintf(stderr, "founder enabled topic lock and set all peers to moderator role\n"); do { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_peers_see_same_roles(autotoxes, NUM_GROUP_TOXES, groupnumber)); topic_spam(rng, autotoxes, NUM_GROUP_TOXES, groupnumber); const unsigned int num_demoted = state0->peers->num_peers / 2; fprintf(stderr, "founder demoting %u moderators to user\n", num_demoted); for (size_t i = 0; i < num_demoted; ++i) { tox_group_set_role(tox0, groupnumber, (uint32_t)state0->peers->peer_ids[i], TOX_GROUP_ROLE_USER, &role_err); ck_assert_msg(role_err == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set user. error: %d", role_err); } do { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); } while (!all_peers_see_same_roles(autotoxes, NUM_GROUP_TOXES, groupnumber)); fprintf(stderr, "Remaining moderators spam change non-moderator roles\n"); role_spam(rng, autotoxes, NUM_GROUP_TOXES, num_demoted, groupnumber); fprintf(stderr, "All peers see the same roles\n"); for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { tox_group_leave(autotoxes[i].tox, groupnumber, nullptr, 0, nullptr); State *state = (State *)autotoxes[i].state; peers_cleanup(state->peers); } fprintf(stderr, "All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_sync_test, sizeof(State), &autotest_opts); return 0; } #undef NUM_GROUP_TOXES #undef ROLE_SPAM_ITERATIONS #undef TOPIC_SPAM_ITERATIONS c-toxcore-0.2.20/auto_tests/group_tcp_test.c0000644060175106017510000002033714714247532017103 0ustar robin/* * Does a basic functionality test for TCP connections. */ #include #include #include #include "auto_test_support.h" #define NUM_GROUP_TOXES 2 #define CODEWORD "RONALD MCDONALD" #define CODEWORD_LEN (sizeof(CODEWORD) - 1) typedef struct State { size_t num_peers; bool got_code; bool got_second_code; uint32_t peer_id[NUM_GROUP_TOXES - 1]; } State; static void group_invite_handler(const Tox_Event_Group_Invite *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t friend_number = tox_event_group_invite_get_friend_number(event); const uint8_t *invite_data = tox_event_group_invite_get_invite_data(event); const size_t length = tox_event_group_invite_get_invite_data_length(event); printf("Accepting friend invite\n"); Tox_Err_Group_Invite_Accept err_accept; tox_group_invite_accept(autotox->tox, friend_number, invite_data, length, (const uint8_t *)"test", 4, nullptr, 0, &err_accept); ck_assert(err_accept == TOX_ERR_GROUP_INVITE_ACCEPT_OK); } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); fprintf(stderr, "joined: %zu, %u\n", state->num_peers, peer_id); ck_assert_msg(state->num_peers < NUM_GROUP_TOXES - 1, "%zu", state->num_peers); state->peer_id[state->num_peers++] = peer_id; } static void group_private_message_handler(const Tox_Event_Group_Private_Message *event, void *user_data) { const uint8_t *message = tox_event_group_private_message_get_message(event); const size_t length = tox_event_group_private_message_get_message_length(event); AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ck_assert(length == CODEWORD_LEN); ck_assert(memcmp(CODEWORD, message, length) == 0); printf("Codeword: %s\n", CODEWORD); state->got_code = true; } static void group_message_handler(const Tox_Event_Group_Message *event, void *user_data) { const uint8_t *message = tox_event_group_message_get_message(event); const size_t length = tox_event_group_message_get_message_length(event); AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; ck_assert(length == CODEWORD_LEN); ck_assert(memcmp(CODEWORD, message, length) == 0); printf("Codeword: %s\n", CODEWORD); state->got_second_code = true; } /* * We need different constants to make TCP run smoothly. TODO(Jfreegman): is this because of the group * implementation or just an autotest quirk? */ #define GROUP_ITERATION_INTERVAL 100 static void iterate_group(AutoTox *autotoxes, uint32_t num_toxes, size_t interval) { for (uint32_t i = 0; i < num_toxes; i++) { if (autotoxes[i].alive) { tox_iterate(autotoxes[i].tox, &autotoxes[i]); autotoxes[i].clock += interval; } } c_sleep(50); } static bool all_peers_connected(AutoTox *autotoxes) { iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); size_t count = 0; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; if (state->num_peers == NUM_GROUP_TOXES - 1) { ++count; } } return count == NUM_GROUP_TOXES; } static bool all_peers_got_code(AutoTox *autotoxes) { iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); size_t count = 0; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { const State *state = (const State *)autotoxes[i].state; if (state->got_code) { ++count; } } return count == NUM_GROUP_TOXES - 1; } static void group_tcp_test(AutoTox *autotoxes) { ck_assert(NUM_GROUP_TOXES >= 2); State *state0 = (State *)autotoxes[0].state; State *state1 = (State *)autotoxes[1].state; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_peer_join(autotoxes[i].dispatch, group_peer_join_handler); tox_events_callback_group_private_message(autotoxes[i].dispatch, group_private_message_handler); } tox_events_callback_group_message(autotoxes[1].dispatch, group_message_handler); tox_events_callback_group_invite(autotoxes[1].dispatch, group_invite_handler); Tox_Err_Group_New new_err; uint32_t groupnumber = tox_group_new(autotoxes[0].tox, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4, (const uint8_t *)"test", 4, &new_err); ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err); iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(autotoxes[0].tox, groupnumber, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "%d", id_err); printf("Tox 0 created new group...\n"); for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { Tox_Err_Group_Join jerr; tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"test", 4, nullptr, 0, &jerr); ck_assert_msg(jerr == TOX_ERR_GROUP_JOIN_OK, "%d", jerr); iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL * 10); } while (!all_peers_connected(autotoxes)) ; printf("%d peers successfully joined. Waiting for code...\n", NUM_GROUP_TOXES); printf("Tox 0 sending secret code to all peers\n"); for (size_t i = 0; i < NUM_GROUP_TOXES - 1; ++i) { Tox_Err_Group_Send_Private_Message perr; tox_group_send_private_message(autotoxes[0].tox, groupnumber, state0->peer_id[i], TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)CODEWORD, CODEWORD_LEN, &perr); ck_assert_msg(perr == TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK, "%d", perr); } while (!all_peers_got_code(autotoxes)) ; Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[1].tox, groupnumber, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); state0->num_peers = 0; state1->num_peers = 0; // now do a friend invite to make sure the TCP-specific logic for friend invites is okay printf("Tox1 leaves group and Tox0 does a friend group invite for tox1\n"); Tox_Err_Group_Invite_Friend err_invite; tox_group_invite_friend(autotoxes[0].tox, groupnumber, 0, &err_invite); ck_assert(err_invite == TOX_ERR_GROUP_INVITE_FRIEND_OK); while (state0->num_peers == 0 && state1->num_peers == 0) { iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); } printf("Tox 1 successfully joined. Waiting for code...\n"); Tox_Err_Group_Send_Message merr; tox_group_send_message(autotoxes[0].tox, groupnumber, TOX_MESSAGE_TYPE_NORMAL, (const uint8_t *)CODEWORD, CODEWORD_LEN, &merr); ck_assert(merr == TOX_ERR_GROUP_SEND_MESSAGE_OK); while (!state1->got_second_code) { iterate_group(autotoxes, NUM_GROUP_TOXES, GROUP_ITERATION_INTERVAL); } for (size_t i = 0; i < NUM_GROUP_TOXES; i++) { tox_group_leave(autotoxes[i].tox, groupnumber, nullptr, 0, &err_exit); ck_assert(err_exit == TOX_ERR_GROUP_LEAVE_OK); } printf("Test passed!\n"); } int main(int argc, char **argv) { setvbuf(stdout, nullptr, _IONBF, 0); struct Tox_Options *options = tox_options_new(nullptr); ck_assert(options != nullptr); tox_options_set_udp_enabled(options, false); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; // TODO(JFreegman): Fix this test and remove the "if". if (argc > 2) { run_auto_test(options, NUM_GROUP_TOXES, group_tcp_test, sizeof(State), &autotest_opts); } tox_options_free(options); return 0; } #undef CODEWORD_LEN #undef CODEWORD #undef NUM_GROUP_TOXES c-toxcore-0.2.20/auto_tests/group_topic_test.c0000644060175106017510000003053614714247532017435 0ustar robin/* * Tests that we can successfully change the group topic, that all peers receive topic changes * and that the topic lock works as intended. */ #include #include #include #include #include "auto_test_support.h" #include "check_compat.h" #include "../toxcore/tox.h" #include "../toxcore/group_chats.h" #define NUM_GROUP_TOXES 3 #define TOPIC "They're waiting for you Gordon...in the test chamber" #define TOPIC_LEN (sizeof(TOPIC) - 1) #define TOPIC2 "They're waiting for you Gordon...in the test chamber 2.0" #define TOPIC_LEN2 (sizeof(TOPIC2) - 1) #define GROUP_NAME "The Test Chamber" #define GROUP_NAME_LEN (sizeof(GROUP_NAME) - 1) #define PEER0_NICK "Koresh" #define PEER0_NICK_LEN (sizeof(PEER0_NICK) - 1) typedef struct State { uint32_t peer_id; // the id of the peer we set to observer } State; static bool all_group_peers_connected(const AutoTox *autotoxes, uint32_t tox_count, uint32_t groupnumber, size_t name_length, uint32_t peer_limit) { for (uint32_t i = 0; i < tox_count; ++i) { // make sure we got an invite if (tox_group_get_name_size(autotoxes[i].tox, groupnumber, nullptr) != name_length) { return false; } // make sure we got a sync response if (peer_limit != 0 && tox_group_get_peer_limit(autotoxes[i].tox, groupnumber, nullptr) != peer_limit) { return false; } // make sure we're actually connected if (!tox_group_is_connected(autotoxes[i].tox, groupnumber, nullptr)) { return false; } } return true; } static void group_peer_join_handler(const Tox_Event_Group_Peer_Join *event, void *user_data) { //const uint32_t group_number = tox_event_group_peer_join_get_group_number(event); const uint32_t peer_id = tox_event_group_peer_join_get_peer_id(event); AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); State *state = (State *)autotox->state; state->peer_id = peer_id; } static void group_topic_handler(const Tox_Event_Group_Topic *event, void *user_data) { AutoTox *autotox = (AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t group_number = tox_event_group_topic_get_group_number(event); //const uint32_t peer_id = tox_event_group_topic_get_peer_id(event); const uint8_t *topic = tox_event_group_topic_get_topic(event); const uint32_t topic_length = tox_event_group_topic_get_topic_length(event); ck_assert(topic_length <= TOX_GROUP_MAX_TOPIC_LENGTH); Tox_Err_Group_State_Query query_err; uint8_t topic2[TOX_GROUP_MAX_TOPIC_LENGTH]; tox_group_get_topic(autotox->tox, group_number, topic2, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); size_t topic_length_getter = tox_group_get_topic_size(autotox->tox, group_number, &query_err); ck_assert(query_err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(topic_length_getter == topic_length && memcmp(topic, topic2, topic_length) == 0, "topic differs in callback: %s, %s", topic, topic2); } static void group_topic_lock_handler(const Tox_Event_Group_Topic_Lock *event, void *user_data) { const AutoTox *autotox = (const AutoTox *)user_data; ck_assert(autotox != nullptr); const uint32_t group_number = tox_event_group_topic_lock_get_group_number(event); const Tox_Group_Topic_Lock topic_lock = tox_event_group_topic_lock_get_topic_lock(event); Tox_Err_Group_State_Query err; Tox_Group_Topic_Lock current_lock = tox_group_get_topic_lock(autotox->tox, group_number, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); ck_assert_msg(topic_lock == current_lock, "topic locks differ in callback"); } /* Sets group topic. * * Return true on success. */ static bool set_topic(Tox *tox, uint32_t groupnumber, const char *topic, size_t length) { Tox_Err_Group_Topic_Set err; tox_group_set_topic(tox, groupnumber, (const uint8_t *)topic, length, &err); return err == TOX_ERR_GROUP_TOPIC_SET_OK; } /* Returns 0 if group topic matches expected topic. * Returns a value < 0 on failure. */ static int check_topic(const Tox *tox, uint32_t groupnumber, const char *expected_topic, size_t expected_length) { Tox_Err_Group_State_Query query_err; size_t topic_length = tox_group_get_topic_size(tox, groupnumber, &query_err); if (query_err != TOX_ERR_GROUP_STATE_QUERY_OK) { return -1; } if (expected_length != topic_length) { return -2; } uint8_t topic[TOX_GROUP_MAX_TOPIC_LENGTH]; tox_group_get_topic(tox, groupnumber, topic, &query_err); if (query_err != TOX_ERR_GROUP_STATE_QUERY_OK) { return -3; } if (memcmp(expected_topic, (const char *)topic, topic_length) != 0) { return -4; } return 0; } static void wait_topic_lock(AutoTox *autotoxes, uint32_t groupnumber, Tox_Group_Topic_Lock expected_lock) { while (1) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); uint32_t count = 0; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { Tox_Err_Group_State_Query err; Tox_Group_Topic_Lock topic_lock = tox_group_get_topic_lock(autotoxes[i].tox, groupnumber, &err); ck_assert(err == TOX_ERR_GROUP_STATE_QUERY_OK); if (topic_lock == expected_lock) { ++count; } } if (count == NUM_GROUP_TOXES) { break; } } } /* Waits for all peers in group to see the same topic */ static void wait_state_topic(AutoTox *autotoxes, uint32_t groupnumber, const char *topic, size_t length) { while (1) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); uint32_t count = 0; for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { const int c_ret = check_topic(autotoxes[i].tox, groupnumber, topic, length); if (c_ret == 0) { ++count; } } if (count == NUM_GROUP_TOXES) { break; } } } /* All peers attempt to set the topic. * * Returns the number of peers who succeeeded. */ static uint32_t set_topic_all_peers(const Random *rng, AutoTox *autotoxes, size_t num_peers, uint32_t groupnumber) { uint32_t change_count = 0; for (size_t i = 0; i < num_peers; ++i) { char new_topic[TOX_GROUP_MAX_TOPIC_LENGTH]; snprintf(new_topic, sizeof(new_topic), "peer %zu changes topic %u", i, random_u32(rng)); size_t length = strlen(new_topic); if (set_topic(autotoxes[i].tox, groupnumber, new_topic, length)) { wait_state_topic(autotoxes, groupnumber, new_topic, length); ++change_count; } else { fprintf(stderr, "Peer %zu couldn't set the topic\n", i); } } return change_count; } static void group_topic_test(AutoTox *autotoxes) { ck_assert_msg(NUM_GROUP_TOXES >= 3, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES); const Random *rng = os_random(); ck_assert(rng != nullptr); Tox *tox0 = autotoxes[0].tox; Tox_Dispatch *dispatch0 = autotoxes[0].dispatch; const State *state0 = (const State *)autotoxes[0].state; tox_events_callback_group_peer_join(dispatch0, group_peer_join_handler); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { tox_events_callback_group_topic(autotoxes[i].dispatch, group_topic_handler); tox_events_callback_group_topic_lock(autotoxes[i].dispatch, group_topic_lock_handler); } /* Tox1 creates a group and is the founder of a newly created group */ Tox_Err_Group_New new_err; const uint32_t groupnumber = tox_group_new(tox0, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)GROUP_NAME, GROUP_NAME_LEN, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, &new_err); ck_assert_msg(new_err == TOX_ERR_GROUP_NEW_OK, "tox_group_new failed: %d", new_err); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); /* Founder sets group topic before anyone else joins */ const bool s_ret = set_topic(tox0, groupnumber, TOPIC, TOPIC_LEN); ck_assert_msg(s_ret, "Founder failed to set topic"); /* Founder gets the Chat ID and implicitly shares it publicly */ Tox_Err_Group_State_Query id_err; uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE]; tox_group_get_chat_id(tox0, groupnumber, chat_id, &id_err); ck_assert_msg(id_err == TOX_ERR_GROUP_STATE_QUERY_OK, "tox_group_get_chat_id failed %d", id_err); /* All other peers join the group using the Chat ID */ for (size_t i = 1; i < NUM_GROUP_TOXES; ++i) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); Tox_Err_Group_Join join_err; tox_group_join(autotoxes[i].tox, chat_id, (const uint8_t *)"Test", 4, nullptr, 0, &join_err); ck_assert_msg(join_err == TOX_ERR_GROUP_JOIN_OK, "tox_group_join failed: %d", join_err); c_sleep(100); } fprintf(stderr, "Peers attempting to join group\n"); all_group_peers_connected(autotoxes, NUM_GROUP_TOXES, groupnumber, GROUP_NAME_LEN, MAX_GC_PEERS_DEFAULT); wait_state_topic(autotoxes, groupnumber, TOPIC, TOPIC_LEN); /* Founder disables topic lock */ Tox_Err_Group_Set_Topic_Lock lock_set_err; tox_group_set_topic_lock(tox0, groupnumber, TOX_GROUP_TOPIC_LOCK_DISABLED, &lock_set_err); ck_assert_msg(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK, "failed to disable topic lock: %d", lock_set_err); fprintf(stderr, "Topic lock disabled\n"); /* make sure every peer sees the topic lock state change */ wait_topic_lock(autotoxes, groupnumber, TOX_GROUP_TOPIC_LOCK_DISABLED); /* All peers should be able to change the topic now */ uint32_t change_count = set_topic_all_peers(rng, autotoxes, NUM_GROUP_TOXES, groupnumber); ck_assert_msg(change_count == NUM_GROUP_TOXES, "%u peers changed the topic with topic lock disabled", change_count); /* founder silences the last peer he saw join */ Tox_Err_Group_Set_Role merr; tox_group_set_role(tox0, groupnumber, state0->peer_id, TOX_GROUP_ROLE_OBSERVER, &merr); ck_assert_msg(merr == TOX_ERR_GROUP_SET_ROLE_OK, "Failed to set %u to observer role: %d", state0->peer_id, merr); fprintf(stderr, "Random peer is set to observer\n"); iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); /* All peers except one should now be able to change the topic */ change_count = set_topic_all_peers(rng, autotoxes, NUM_GROUP_TOXES, groupnumber); ck_assert_msg(change_count == NUM_GROUP_TOXES - 1, "%u peers changed the topic with a silenced peer", change_count); /* Founder enables topic lock and sets topic back to original */ tox_group_set_topic_lock(tox0, groupnumber, TOX_GROUP_TOPIC_LOCK_ENABLED, &lock_set_err); ck_assert_msg(lock_set_err == TOX_ERR_GROUP_SET_TOPIC_LOCK_OK, "failed to enable topic lock: %d", lock_set_err); fprintf(stderr, "Topic lock enabled\n"); /* Wait for all peers to get topic lock state change */ wait_topic_lock(autotoxes, groupnumber, TOX_GROUP_TOPIC_LOCK_ENABLED); const bool s3_ret = set_topic(tox0, groupnumber, TOPIC2, TOPIC_LEN2); ck_assert_msg(s3_ret, "Founder failed to set topic second time"); wait_state_topic(autotoxes, groupnumber, TOPIC2, TOPIC_LEN2); /* No peer excluding the founder should be able to set the topic */ change_count = set_topic_all_peers(rng, &autotoxes[1], NUM_GROUP_TOXES - 1, groupnumber); ck_assert_msg(change_count == 0, "%u peers changed the topic with topic lock enabled", change_count); /* A final check that the topic is unchanged */ wait_state_topic(autotoxes, groupnumber, TOPIC2, TOPIC_LEN2); for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) { Tox_Err_Group_Leave err_exit; tox_group_leave(autotoxes[i].tox, groupnumber, nullptr, 0, &err_exit); ck_assert_msg(err_exit == TOX_ERR_GROUP_LEAVE_OK, "%d", err_exit); } fprintf(stderr, "All tests passed!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options autotest_opts = default_run_auto_options(); autotest_opts.graph = GRAPH_COMPLETE; run_auto_test(nullptr, NUM_GROUP_TOXES, group_topic_test, sizeof(State), &autotest_opts); return 0; } #undef TOPIC #undef TOPIC_LEN #undef TOPIC2 #undef TOPIC_LEN2 #undef NUM_GROUP_TOXES #undef GROUP_NAME #undef GROUP_NAME_LEN #undef PEER0_NICK #undef PEER0_NICK_LEN c-toxcore-0.2.20/auto_tests/invalid_tcp_proxy_test.c0000644060175106017510000000241214714247532020630 0ustar robin// Test to make sure that when UDP is disabled, and we set an invalid proxy, // i.e. one that doesn't run a proxy server, then we don't get any connection. #include #include "../testing/misc_tools.h" #include "auto_test_support.h" #include "check_compat.h" // Try to bootstrap for 20 seconds. #define NUM_ITERATIONS (unsigned)(20.0 / (ITERATION_INTERVAL / 1000.0)) int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); struct Tox_Options *opts = tox_options_new(nullptr); tox_options_set_udp_enabled(opts, false); tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_SOCKS5); tox_options_set_proxy_host(opts, "127.0.0.1"); tox_options_set_proxy_port(opts, 51724); Tox *tox = tox_new_log(opts, nullptr, nullptr); tox_options_free(opts); bootstrap_tox_live_network(tox, true); printf("Waiting for connection...\n"); for (uint16_t i = 0; i < NUM_ITERATIONS; i++) { tox_iterate(tox, nullptr); c_sleep(ITERATION_INTERVAL); // None of the iterations should have a connection. const Tox_Connection status = tox_self_get_connection_status(tox); ck_assert_msg(status == TOX_CONNECTION_NONE, "unexpectedly got a connection (%d)", status); } tox_kill(tox); return 0; } c-toxcore-0.2.20/auto_tests/invalid_udp_proxy_test.c0000644060175106017510000000233214714247532020633 0ustar robin// Test that if UDP is enabled, and a proxy is provided that does not support // UDP proxying, we disable UDP. #include #include "../testing/misc_tools.h" #include "auto_test_support.h" #include "check_compat.h" // Try to bootstrap for 20 seconds. #define NUM_ITERATIONS (unsigned)(20.0 / (ITERATION_INTERVAL / 1000.0)) int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); struct Tox_Options *opts = tox_options_new(nullptr); tox_options_set_udp_enabled(opts, true); tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_SOCKS5); tox_options_set_proxy_host(opts, "127.0.0.1"); tox_options_set_proxy_port(opts, 51724); Tox *tox = tox_new_log(opts, nullptr, nullptr); tox_options_free(opts); bootstrap_tox_live_network(tox, true); printf("Waiting for connection..."); for (uint16_t i = 0; i < NUM_ITERATIONS; i++) { tox_iterate(tox, nullptr); c_sleep(ITERATION_INTERVAL); // None of the iterations should have a connection. const Tox_Connection status = tox_self_get_connection_status(tox); ck_assert_msg(status == TOX_CONNECTION_NONE, "unexpectedly got a connection (%d)", status); } tox_kill(tox); return 0; } c-toxcore-0.2.20/auto_tests/lan_discovery_test.c0000644060175106017510000000277314714247532017746 0ustar robin#include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox_struct.h" #include "auto_test_support.h" static uint64_t get_state_clock_callback(void *user_data) { const uint64_t *clock = (const uint64_t *)user_data; return *clock; } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Tox *tox1 = tox_new_log_lan(nullptr, nullptr, nullptr, /* lan_discovery */true); Tox *tox2 = tox_new_log_lan(nullptr, nullptr, nullptr, /* lan_discovery */true); ck_assert(tox1 != nullptr); ck_assert(tox2 != nullptr); uint64_t clock = current_time_monotonic(tox1->mono_time); Mono_Time *mono_time; mono_time = tox1->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock); mono_time = tox2->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock); printf("Waiting for LAN discovery. This loop will attempt to run until successful."); do { printf("."); fflush(stdout); tox_iterate(tox1, nullptr); tox_iterate(tox2, nullptr); c_sleep(5); clock += 100; } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE); printf(" %d <-> %d\n", tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2)); tox_kill(tox2); tox_kill(tox1); return 0; } c-toxcore-0.2.20/auto_tests/lossless_packet_test.c0000644060175106017510000000447514714247532020304 0ustar robin/* Tests that we can send lossless packets. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/util.h" #include "check_compat.h" typedef struct State { bool custom_packet_received; } State; #include "auto_test_support.h" #define LOSSLESS_PACKET_FILLER 160 static void handle_lossless_packet(const Tox_Event_Friend_Lossless_Packet *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_lossless_packet_get_friend_number(event); const uint8_t *data = tox_event_friend_lossless_packet_get_data(event); const uint32_t data_length = tox_event_friend_lossless_packet_get_data_length(event); uint8_t *cmp_packet = (uint8_t *)malloc(tox_max_custom_packet_size()); ck_assert(cmp_packet != nullptr); memset(cmp_packet, LOSSLESS_PACKET_FILLER, tox_max_custom_packet_size()); if (data_length == tox_max_custom_packet_size() && memcmp(data, cmp_packet, tox_max_custom_packet_size()) == 0) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; state->custom_packet_received = true; } free(cmp_packet); } static void test_lossless_packet(AutoTox *autotoxes) { tox_events_callback_friend_lossless_packet(autotoxes[1].dispatch, &handle_lossless_packet); const size_t packet_size = tox_max_custom_packet_size() + 1; uint8_t *packet = (uint8_t *)malloc(packet_size); ck_assert(packet != nullptr); memset(packet, LOSSLESS_PACKET_FILLER, packet_size); bool ret = tox_friend_send_lossless_packet(autotoxes[0].tox, 0, packet, packet_size, nullptr); ck_assert_msg(ret == false, "should not be able to send custom packets this big %i", ret); ret = tox_friend_send_lossless_packet(autotoxes[0].tox, 0, packet, tox_max_custom_packet_size(), nullptr); ck_assert_msg(ret == true, "tox_friend_send_lossless_packet fail %i", ret); free(packet); do { iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } while (!((State *)autotoxes[1].state)->custom_packet_received); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, test_lossless_packet, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/lossy_packet_test.c0000644060175106017510000000441514714247532017600 0ustar robin/* Tests that we can send lossy packets. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/util.h" #include "check_compat.h" typedef struct State { bool custom_packet_received; } State; #include "auto_test_support.h" #define LOSSY_PACKET_FILLER 200 static void handle_lossy_packet(const Tox_Event_Friend_Lossy_Packet *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_lossy_packet_get_friend_number(event); const uint8_t *data = tox_event_friend_lossy_packet_get_data(event); const uint32_t data_length = tox_event_friend_lossy_packet_get_data_length(event); uint8_t *cmp_packet = (uint8_t *)malloc(tox_max_custom_packet_size()); ck_assert(cmp_packet != nullptr); memset(cmp_packet, LOSSY_PACKET_FILLER, tox_max_custom_packet_size()); if (data_length == tox_max_custom_packet_size() && memcmp(data, cmp_packet, tox_max_custom_packet_size()) == 0) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; state->custom_packet_received = true; } free(cmp_packet); } static void test_lossy_packet(AutoTox *autotoxes) { tox_events_callback_friend_lossy_packet(autotoxes[1].dispatch, &handle_lossy_packet); const size_t packet_size = tox_max_custom_packet_size() + 1; uint8_t *packet = (uint8_t *)malloc(packet_size); ck_assert(packet != nullptr); memset(packet, LOSSY_PACKET_FILLER, packet_size); bool ret = tox_friend_send_lossy_packet(autotoxes[0].tox, 0, packet, packet_size, nullptr); ck_assert_msg(ret == false, "should not be able to send custom packets this big %i", ret); ret = tox_friend_send_lossy_packet(autotoxes[0].tox, 0, packet, tox_max_custom_packet_size(), nullptr); ck_assert_msg(ret == true, "tox_friend_send_lossy_packet fail %i", ret); free(packet); do { iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } while (!((State *)autotoxes[1].state)->custom_packet_received); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, test_lossy_packet, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/Makefile.inc0000644060175106017510000001771314714247532016112 0ustar robinif BUILD_TESTS noinst_LTLIBRARIES += libauto_test_support.la libauto_test_support_la_SOURCES = ../auto_tests/auto_test_support.c ../auto_tests/auto_test_support.h libauto_test_support_la_LIBADD = libmisc_tools.la libtoxcore.la TESTS = \ announce_test \ conference_double_invite_test \ conference_invite_merge_test \ conference_peer_nick_test \ conference_simple_test \ conference_test \ conference_two_test \ crypto_test \ encryptsave_test \ file_saving_test \ file_streaming_test \ file_transfer_test \ forwarding_test \ friend_connection_test \ friend_request_test \ group_state_test \ invalid_tcp_proxy_test \ invalid_udp_proxy_test \ lan_discovery_test \ lossless_packet_test \ lossy_packet_test \ network_test \ onion_test \ overflow_recvq_test \ overflow_sendq_test \ reconnect_test \ save_compatibility_test \ save_friend_test \ send_message_test \ set_name_test \ set_status_message_test \ TCP_test \ tox_dispatch_test \ tox_events_test \ tox_many_tcp_test \ tox_many_test \ tox_strncasecmp_test \ typing_test \ version_test AUTOTEST_CFLAGS = \ $(LIBSODIUM_CFLAGS) AUTOTEST_LDADD = \ $(LIBSODIUM_LDFLAGS) \ libmisc_tools.la \ libauto_test_support.la \ libtoxcore.la \ libtoxencryptsave.la \ $(LIBSODIUM_LIBS) if BUILD_AV TESTS += conference_av_test toxav_basic_test toxav_many_test AUTOTEST_LDADD += libtoxav.la endif check_PROGRAMS = $(TESTS) announce_test_SOURCES = ../auto_tests/announce_test.c announce_test_CFLAGS = $(AUTOTEST_CFLAGS) announce_test_LDADD = $(AUTOTEST_LDADD) conference_double_invite_test_SOURCES = ../auto_tests/conference_double_invite_test.c conference_double_invite_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_double_invite_test_LDADD = $(AUTOTEST_LDADD) conference_invite_merge_test_SOURCES = ../auto_tests/conference_invite_merge_test.c conference_invite_merge_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_invite_merge_test_LDADD = $(AUTOTEST_LDADD) conference_peer_nick_test_SOURCES = ../auto_tests/conference_peer_nick_test.c conference_peer_nick_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_peer_nick_test_LDADD = $(AUTOTEST_LDADD) conference_simple_test_SOURCES = ../auto_tests/conference_simple_test.c conference_simple_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_simple_test_LDADD = $(AUTOTEST_LDADD) conference_test_SOURCES = ../auto_tests/conference_test.c conference_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_test_LDADD = $(AUTOTEST_LDADD) conference_two_test_SOURCES = ../auto_tests/conference_two_test.c conference_two_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_two_test_LDADD = $(AUTOTEST_LDADD) crypto_test_SOURCES = ../auto_tests/crypto_test.c crypto_test_CFLAGS = $(AUTOTEST_CFLAGS) crypto_test_LDADD = $(AUTOTEST_LDADD) encryptsave_test_SOURCES = ../auto_tests/encryptsave_test.c encryptsave_test_CFLAGS = $(AUTOTEST_CFLAGS) encryptsave_test_LDADD = $(AUTOTEST_LDADD) file_saving_test_SOURCES = ../auto_tests/file_saving_test.c file_saving_test_CFLAGS = $(AUTOTEST_CFLAGS) file_saving_test_LDADD = $(AUTOTEST_LDADD) file_streaming_test_SOURCES = ../auto_tests/file_streaming_test.c file_streaming_test_CFLAGS = $(AUTOTEST_CFLAGS) file_streaming_test_LDADD = $(AUTOTEST_LDADD) file_transfer_test_SOURCES = ../auto_tests/file_transfer_test.c file_transfer_test_CFLAGS = $(AUTOTEST_CFLAGS) file_transfer_test_LDADD = $(AUTOTEST_LDADD) forwarding_test_SOURCES = ../auto_tests/forwarding_test.c forwarding_test_CFLAGS = $(AUTOTEST_CFLAGS) forwarding_test_LDADD = $(AUTOTEST_LDADD) friend_connection_test_SOURCES = ../auto_tests/friend_connection_test.c friend_connection_test_CFLAGS = $(AUTOTEST_CFLAGS) friend_connection_test_LDADD = $(AUTOTEST_LDADD) friend_request_test_SOURCES = ../auto_tests/friend_request_test.c friend_request_test_CFLAGS = $(AUTOTEST_CFLAGS) friend_request_test_LDADD = $(AUTOTEST_LDADD) group_state_test_SOURCES = ../auto_tests/group_state_test.c group_state_test_CFLAGS = $(AUTOTEST_CFLAGS) group_state_test_LDADD = $(AUTOTEST_LDADD) invalid_tcp_proxy_test_SOURCES = ../auto_tests/invalid_tcp_proxy_test.c invalid_tcp_proxy_test_CFLAGS = $(AUTOTEST_CFLAGS) invalid_tcp_proxy_test_LDADD = $(AUTOTEST_LDADD) invalid_udp_proxy_test_SOURCES = ../auto_tests/invalid_udp_proxy_test.c invalid_udp_proxy_test_CFLAGS = $(AUTOTEST_CFLAGS) invalid_udp_proxy_test_LDADD = $(AUTOTEST_LDADD) lan_discovery_test_SOURCES = ../auto_tests/lan_discovery_test.c lan_discovery_test_CFLAGS = $(AUTOTEST_CFLAGS) lan_discovery_test_LDADD = $(AUTOTEST_LDADD) lossless_packet_test_SOURCES = ../auto_tests/lossless_packet_test.c lossless_packet_test_CFLAGS = $(AUTOTEST_CFLAGS) lossless_packet_test_LDADD = $(AUTOTEST_LDADD) lossy_packet_test_SOURCES = ../auto_tests/lossy_packet_test.c lossy_packet_test_CFLAGS = $(AUTOTEST_CFLAGS) lossy_packet_test_LDADD = $(AUTOTEST_LDADD) network_test_SOURCES = ../auto_tests/network_test.c network_test_CFLAGS = $(AUTOTEST_CFLAGS) network_test_LDADD = $(AUTOTEST_LDADD) onion_test_SOURCES = ../auto_tests/onion_test.c onion_test_CFLAGS = $(AUTOTEST_CFLAGS) onion_test_LDADD = $(AUTOTEST_LDADD) overflow_recvq_test_SOURCES = ../auto_tests/overflow_recvq_test.c overflow_recvq_test_CFLAGS = $(AUTOTEST_CFLAGS) overflow_recvq_test_LDADD = $(AUTOTEST_LDADD) overflow_sendq_test_SOURCES = ../auto_tests/overflow_sendq_test.c overflow_sendq_test_CFLAGS = $(AUTOTEST_CFLAGS) overflow_sendq_test_LDADD = $(AUTOTEST_LDADD) reconnect_test_SOURCES = ../auto_tests/reconnect_test.c reconnect_test_CFLAGS = $(AUTO_TEST_CFLAGS) reconnect_test_LDADD = $(AUTOTEST_LDADD) save_compatibility_test_SOURCES = ../auto_tests/save_compatibility_test.c save_compatibility_test_CFLAGS = $(AUTOTEST_CFLAGS) save_compatibility_test_LDADD = $(AUTOTEST_LDADD) save_friend_test_SOURCES = ../auto_tests/save_friend_test.c save_friend_test_CFLAGS = $(AUTOTEST_CFLAGS) save_friend_test_LDADD = $(AUTOTEST_LDADD) send_message_test_SOURCES = ../auto_tests/send_message_test.c send_message_test_CFLAGS = $(AUTOTEST_CFLAGS) send_message_test_LDADD = $(AUTOTEST_LDADD) set_name_test_SOURCES = ../auto_tests/set_name_test.c set_name_test_CFLAGS = $(AUTOTEST_CFLAGS) set_name_test_LDADD = $(AUTOTEST_LDADD) set_status_message_test_SOURCES = ../auto_tests/set_status_message_test.c set_status_message_test_CFLAGS = $(AUTOTEST_CFLAGS) set_status_message_test_LDADD = $(AUTOTEST_LDADD) TCP_test_SOURCES = ../auto_tests/TCP_test.c TCP_test_CFLAGS = $(AUTOTEST_CFLAGS) TCP_test_LDADD = $(AUTOTEST_LDADD) tox_dispatch_test_SOURCES = ../auto_tests/tox_dispatch_test.c tox_dispatch_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_dispatch_test_LDADD = $(AUTOTEST_LDADD) tox_events_test_SOURCES = ../auto_tests/tox_events_test.c tox_events_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_events_test_LDADD = $(AUTOTEST_LDADD) tox_many_tcp_test_SOURCES = ../auto_tests/tox_many_tcp_test.c tox_many_tcp_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_many_tcp_test_LDADD = $(AUTOTEST_LDADD) tox_many_test_SOURCES = ../auto_tests/tox_many_test.c tox_many_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_many_test_LDADD = $(AUTOTEST_LDADD) tox_strncasecmp_test_SOURCES = ../auto_tests/tox_strncasecmp_test.c tox_strncasecmp_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_strncasecmp_test_LDADD = $(AUTOTEST_LDADD) typing_test_SOURCES = ../auto_tests/typing_test.c typing_test_CFLAGS = $(AUTOTEST_CFLAGS) typing_test_LDADD = $(AUTOTEST_LDADD) version_test_SOURCES = ../auto_tests/version_test.c version_test_CFLAGS = $(AUTOTEST_CFLAGS) version_test_LDADD = $(AUTOTEST_LDADD) if BUILD_AV conference_av_test_SOURCES = ../auto_tests/conference_av_test.c conference_av_test_CFLAGS = $(AUTOTEST_CFLAGS) conference_av_test_LDADD = $(AUTOTEST_LDADD) toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS) toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS) toxav_many_test_LDADD = $(AUTOTEST_LDADD) endif endif EXTRA_DIST += \ $(top_srcdir)/auto_tests/data/save.tox.big \ $(top_srcdir)/auto_tests/data/save.tox.little \ $(top_srcdir)/auto_tests/check_compat.h \ $(top_srcdir)/auto_tests/auto_test_support.h c-toxcore-0.2.20/auto_tests/network_test.c0000644060175106017510000001333314714247532016570 0ustar robin#include #include #include "../testing/misc_tools.h" #include "../toxcore/network.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif static void test_addr_resolv_localhost(void) { #ifdef __CYGWIN__ /* force initialization of network stack * normally this should happen automatically * cygwin doesn't do it for every network related function though * e.g. not for getaddrinfo... */ net_socket(0, 0, 0); errno = 0; #endif const Network *ns = os_network(); ck_assert(ns != nullptr); const char localhost[] = "localhost"; IP ip; ip_init(&ip, 0); // ipv6enabled = 0 bool res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr); int error = net_error(); char *strerror = net_new_strerror(error); ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror); net_kill_strerror(strerror); Ip_Ntoa ip_str; ck_assert_msg(net_family_is_ipv4(ip.family), "Expected family TOX_AF_INET, got %u.", ip.family.value); const uint32_t loopback = get_ip4_loopback().uint32; ck_assert_msg(ip.ip.v4.uint32 == loopback, "Expected 127.0.0.1, got %s.", net_ip_ntoa(&ip, &ip_str)); ip_init(&ip, 1); // ipv6enabled = 1 res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr); #if USE_IPV6 int localhost_split = 0; if (!net_family_is_ipv6(ip.family)) { res = addr_resolve_or_parse_ip(ns, "ip6-localhost", &ip, nullptr); localhost_split = 1; } error = net_error(); strerror = net_new_strerror(error); ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror); net_kill_strerror(strerror); ck_assert_msg(net_family_is_ipv6(ip.family), "Expected family TOX_AF_INET6 (%d), got %u.", TOX_AF_INET6, ip.family.value); IP6 ip6_loopback = get_ip6_loopback(); ck_assert_msg(!memcmp(&ip.ip.v6, &ip6_loopback, sizeof(IP6)), "Expected ::1, got %s.", net_ip_ntoa(&ip, &ip_str)); if (localhost_split) { printf("Localhost seems to be split in two.\n"); return; } #endif ip_init(&ip, 1); // ipv6enabled = 1 ip.family = net_family_unspec(); IP extra; ip_reset(&extra); res = addr_resolve_or_parse_ip(ns, localhost, &ip, &extra); error = net_error(); strerror = net_new_strerror(error); ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror); net_kill_strerror(strerror); #if USE_IPV6 ck_assert_msg(net_family_is_ipv6(ip.family), "Expected family TOX_AF_INET6 (%d), got %u.", TOX_AF_INET6, ip.family.value); ck_assert_msg(!memcmp(&ip.ip.v6, &ip6_loopback, sizeof(IP6)), "Expected ::1, got %s.", net_ip_ntoa(&ip, &ip_str)); ck_assert_msg(net_family_is_ipv4(extra.family), "Expected family TOX_AF_INET (%d), got %u.", TOX_AF_INET, extra.family.value); ck_assert_msg(extra.ip.v4.uint32 == loopback, "Expected 127.0.0.1, got %s.", net_ip_ntoa(&ip, &ip_str)); #elif 0 // TODO(iphydf): Fix this to work on IPv6-supporting systems. ck_assert_msg(net_family_is_ipv4(ip.family), "Expected family TOX_AF_INET (%d), got %u.", TOX_AF_INET, ip.family.value); ck_assert_msg(ip.ip.v4.uint32 == loopback, "Expected 127.0.0.1, got %s.", net_ip_ntoa(&ip, &ip_str)); #endif } static void test_ip_equal(void) { int res; IP ip1, ip2; ip_reset(&ip1); ip_reset(&ip2); res = ip_equal(nullptr, nullptr); ck_assert_msg(res == 0, "ip_equal(NULL, NULL): expected result 0, got %d.", res); res = ip_equal(&ip1, nullptr); ck_assert_msg(res == 0, "ip_equal(PTR, NULL): expected result 0, got %d.", res); res = ip_equal(nullptr, &ip1); ck_assert_msg(res == 0, "ip_equal(NULL, PTR): expected result 0, got %d.", res); ip1.family = net_family_ipv4(); ip1.ip.v4.uint32 = net_htonl(0x7F000001); res = ip_equal(&ip1, &ip2); ck_assert_msg(res == 0, "ip_equal( {TOX_AF_INET, 127.0.0.1}, {TOX_AF_UNSPEC, 0} ): " "expected result 0, got %d.", res); ip2.family = net_family_ipv4(); ip2.ip.v4.uint32 = net_htonl(0x7F000001); res = ip_equal(&ip1, &ip2); ck_assert_msg(res != 0, "ip_equal( {TOX_AF_INET, 127.0.0.1}, {TOX_AF_INET, 127.0.0.1} ): " "expected result != 0, got 0."); ip2.ip.v4.uint32 = net_htonl(0x7F000002); res = ip_equal(&ip1, &ip2); ck_assert_msg(res == 0, "ip_equal( {TOX_AF_INET, 127.0.0.1}, {TOX_AF_INET, 127.0.0.2} ): " "expected result 0, got %d.", res); ip2.family = net_family_ipv6(); ip2.ip.v6.uint32[0] = 0; ip2.ip.v6.uint32[1] = 0; ip2.ip.v6.uint32[2] = net_htonl(0xFFFF); ip2.ip.v6.uint32[3] = net_htonl(0x7F000001); ck_assert_msg(ipv6_ipv4_in_v6(&ip2.ip.v6) != 0, "ipv6_ipv4_in_v6(::ffff:127.0.0.1): expected != 0, got 0."); res = ip_equal(&ip1, &ip2); ck_assert_msg(res != 0, "ip_equal( {TOX_AF_INET, 127.0.0.1}, {TOX_AF_INET6, ::ffff:127.0.0.1} ): " "expected result != 0, got 0."); IP6 ip6_loopback = get_ip6_loopback(); memcpy(&ip2.ip.v6, &ip6_loopback, sizeof(IP6)); res = ip_equal(&ip1, &ip2); ck_assert_msg(res == 0, "ip_equal( {TOX_AF_INET, 127.0.0.1}, {TOX_AF_INET6, ::1} ): expected result 0, got %d.", res); memcpy(&ip1, &ip2, sizeof(IP)); res = ip_equal(&ip1, &ip2); ck_assert_msg(res != 0, "ip_equal( {TOX_AF_INET6, ::1}, {TOX_AF_INET6, ::1} ): expected result != 0, got 0."); ip2.ip.v6.uint8[15]++; res = ip_equal(&ip1, &ip2); ck_assert_msg(res == 0, "ip_equal( {TOX_AF_INET6, ::1}, {TOX_AF_INET6, ::2} ): expected result 0, got %d.", res); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_addr_resolv_localhost(); test_ip_equal(); return 0; } c-toxcore-0.2.20/auto_tests/onion_test.c0000644060175106017510000005110014714247532016213 0ustar robin#include #include #include "../testing/misc_tools.h" #include "../toxcore/mono_time.h" #include "../toxcore/onion.h" #include "../toxcore/onion_announce.h" #include "../toxcore/onion_client.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif static inline IP get_loopback(void) { IP ip; #if USE_IPV6 ip.family = net_family_ipv6(); ip.ip.v6 = get_ip6_loopback(); #else ip.family = net_family_ipv4(); ip.ip.v4 = get_ip4_loopback(); #endif return ip; } static void do_onion(Mono_Time *mono_time, Onion *onion) { mono_time_update(mono_time); networking_poll(onion->net, nullptr); do_dht(onion->dht); } static int handled_test_1; static int handle_test_1(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) { const Onion *onion = (const Onion *)object; const char req_message[] = "Install Gentoo"; uint8_t req_packet[1 + sizeof(req_message)]; req_packet[0] = NET_PACKET_ANNOUNCE_REQUEST; memcpy(req_packet + 1, req_message, sizeof(req_message)); if (memcmp(packet, req_packet, sizeof(req_packet)) != 0) { return 1; } const char res_message[] = "install gentoo"; uint8_t res_packet[1 + sizeof(res_message)]; res_packet[0] = NET_PACKET_ANNOUNCE_RESPONSE; memcpy(res_packet + 1, res_message, sizeof(res_message)); if (send_onion_response(onion->log, onion->net, source, res_packet, sizeof(res_packet), packet + sizeof(res_packet)) == -1) { return 1; } handled_test_1 = 1; return 0; } static int handled_test_2; static int handle_test_2(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) { const char res_message[] = "install gentoo"; uint8_t res_packet[1 + sizeof(res_message)]; res_packet[0] = NET_PACKET_ANNOUNCE_RESPONSE; memcpy(res_packet + 1, res_message, sizeof(res_message)); if (length != sizeof(res_packet)) { return 1; } if (memcmp(packet, res_packet, sizeof(res_packet)) != 0) { return 1; } handled_test_2 = 1; return 0; } #if 0 void print_client_id(uint8_t *client_id, uint32_t length) { uint32_t j; for (j = 0; j < length; j++) { printf("%02X", client_id[j]); } printf("\n"); } #endif static uint8_t sb_data[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; static int handled_test_3; static uint8_t test_3_pub_key[CRYPTO_PUBLIC_KEY_SIZE]; static uint8_t test_3_ping_id[CRYPTO_SHA256_SIZE]; static int handle_test_3(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) { const Onion *onion = (const Onion *)object; if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { return 1; } uint8_t plain[2 + CRYPTO_SHA256_SIZE]; #if 0 print_client_id(packet, length); #endif int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht), packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, 2 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain); if (len == -1) { return 1; } if (memcmp(packet + 1, sb_data, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) != 0) { return 1; } memcpy(test_3_ping_id, plain + 1, CRYPTO_SHA256_SIZE); #if 0 print_client_id(test_3_ping_id, sizeof(test_3_ping_id)); #endif handled_test_3 = 1; return 0; } /* TODO: DEPRECATE */ static int handle_test_3_old(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) { const Onion *onion = (const Onion *)object; if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { return 1; } uint8_t plain[2 + CRYPTO_SHA256_SIZE]; #if 0 print_client_id(packet, length); #endif int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht), packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, 1 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain); if (len == -1) { return 1; } if (memcmp(packet + 1, sb_data, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) != 0) { return 1; } memcpy(test_3_ping_id, plain + 1, CRYPTO_SHA256_SIZE); #if 0 print_client_id(test_3_ping_id, sizeof(test_3_ping_id)); #endif handled_test_3 = 1; return 0; } static uint8_t nonce[CRYPTO_NONCE_SIZE]; static int handled_test_4; static int handle_test_4(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata) { const Onion *onion = (const Onion *)object; if (length != (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + sizeof("Install gentoo") + CRYPTO_MAC_SIZE)) { return 1; } uint8_t plain[sizeof("Install gentoo")] = {0}; if (memcmp(nonce, packet + 1, CRYPTO_NONCE_SIZE) != 0) { return 1; } int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, dht_get_self_secret_key(onion->dht), packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, sizeof("Install gentoo") + CRYPTO_MAC_SIZE, plain); if (len == -1) { return 1; } if (memcmp(plain, "Install gentoo", sizeof("Install gentoo")) != 0) { return 1; } handled_test_4 = 1; return 0; } /** Create and send a onion packet. * * Use Onion_Path path to send data of length to dest. * Maximum length of data is ONION_MAX_DATA_SIZE. */ static void send_onion_packet(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length) { uint8_t packet[ONION_MAX_PACKET_SIZE]; const int len = create_onion_packet(rng, packet, sizeof(packet), path, dest, data, length); ck_assert_msg(len != -1, "failed to create onion packet"); ck_assert_msg(sendpacket(net, &path->ip_port1, packet, len) == len, "failed to send onion packet"); } /** Initialize networking. * Added for reverse compatibility with old new_networking calls. */ static Networking_Core *new_networking(const Logger *log, const Memory *mem, const Network *ns, const IP *ip, uint16_t port) { return new_networking_ex(log, mem, ns, ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), nullptr); } static void test_basic(void) { uint32_t index[] = { 1, 2, 3 }; const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); Logger *log1 = logger_new(); logger_callback_log(log1, print_debug_logger, nullptr, &index[0]); Logger *log2 = logger_new(); logger_callback_log(log2, print_debug_logger, nullptr, &index[1]); Mono_Time *mono_time1 = mono_time_new(mem, nullptr, nullptr); Mono_Time *mono_time2 = mono_time_new(mem, nullptr, nullptr); IP ip = get_loopback(); Onion *onion1 = new_onion(log1, mem, mono_time1, rng, new_dht(log1, mem, rng, ns, mono_time1, new_networking(log1, mem, ns, &ip, 36567), true, false)); Onion *onion2 = new_onion(log2, mem, mono_time2, rng, new_dht(log2, mem, rng, ns, mono_time2, new_networking(log2, mem, ns, &ip, 36568), true, false)); ck_assert_msg((onion1 != nullptr) && (onion2 != nullptr), "Onion failed initializing."); networking_registerhandler(onion2->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_test_1, onion2); IP_Port on1 = {ip, net_port(onion1->net)}; Node_format n1; memcpy(n1.public_key, dht_get_self_public_key(onion1->dht), CRYPTO_PUBLIC_KEY_SIZE); n1.ip_port = on1; IP_Port on2 = {ip, net_port(onion2->net)}; Node_format n2; memcpy(n2.public_key, dht_get_self_public_key(onion2->dht), CRYPTO_PUBLIC_KEY_SIZE); n2.ip_port = on2; const char req_message[] = "Install Gentoo"; uint8_t req_packet[1 + sizeof(req_message)]; req_packet[0] = NET_PACKET_ANNOUNCE_REQUEST; memcpy(req_packet + 1, req_message, sizeof(req_message)); Node_format nodes[4]; nodes[0] = n1; nodes[1] = n2; nodes[2] = n1; nodes[3] = n2; Onion_Path path; create_onion_path(rng, onion1->dht, &path, nodes); send_onion_packet(onion1->net, rng, &path, &nodes[3].ip_port, req_packet, sizeof(req_packet)); handled_test_1 = 0; do { do_onion(mono_time1, onion1); do_onion(mono_time2, onion2); } while (handled_test_1 == 0); networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_test_2, onion1); handled_test_2 = 0; do { do_onion(mono_time1, onion1); do_onion(mono_time2, onion2); } while (handled_test_2 == 0); Onion_Announce *onion1_a = new_onion_announce(log1, mem, rng, mono_time1, onion1->dht); Onion_Announce *onion2_a = new_onion_announce(log2, mem, rng, mono_time2, onion2->dht); networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_test_3, onion1); networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, &handle_test_3_old, onion1); ck_assert_msg((onion1_a != nullptr) && (onion2_a != nullptr), "Onion_Announce failed initializing."); const uint8_t zeroes[64] = {0}; random_bytes(rng, sb_data, sizeof(sb_data)); uint64_t s; memcpy(&s, sb_data, sizeof(uint64_t)); memcpy(test_3_pub_key, nodes[3].public_key, CRYPTO_PUBLIC_KEY_SIZE); int ret = send_announce_request(log1, onion1->net, rng, &path, &nodes[3], dht_get_self_public_key(onion1->dht), dht_get_self_secret_key(onion1->dht), zeroes, dht_get_self_public_key(onion1->dht), dht_get_self_public_key(onion1->dht), s); ck_assert_msg(ret == 0, "Failed to create/send onion announce_request packet."); handled_test_3 = 0; do { do_onion(mono_time1, onion1); do_onion(mono_time2, onion2); c_sleep(50); } while (handled_test_3 == 0); printf("test 3 complete\n"); random_bytes(rng, sb_data, sizeof(sb_data)); memcpy(&s, sb_data, sizeof(uint64_t)); memcpy(onion_announce_entry_public_key(onion2_a, 1), dht_get_self_public_key(onion2->dht), CRYPTO_PUBLIC_KEY_SIZE); onion_announce_entry_set_time(onion2_a, 1, mono_time_get(mono_time2)); networking_registerhandler(onion1->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_test_4, onion1); send_announce_request(log1, onion1->net, rng, &path, &nodes[3], dht_get_self_public_key(onion1->dht), dht_get_self_secret_key(onion1->dht), test_3_ping_id, dht_get_self_public_key(onion1->dht), dht_get_self_public_key(onion1->dht), s); do { do_onion(mono_time1, onion1); do_onion(mono_time2, onion2); c_sleep(50); } while (memcmp(onion_announce_entry_public_key(onion2_a, ONION_ANNOUNCE_MAX_ENTRIES - 2), dht_get_self_public_key(onion1->dht), CRYPTO_PUBLIC_KEY_SIZE) != 0); c_sleep(1000); Logger *log3 = logger_new(); logger_callback_log(log3, print_debug_logger, nullptr, &index[2]); Mono_Time *mono_time3 = mono_time_new(mem, nullptr, nullptr); Onion *onion3 = new_onion(log3, mem, mono_time3, rng, new_dht(log3, mem, rng, ns, mono_time3, new_networking(log3, mem, ns, &ip, 36569), true, false)); ck_assert_msg((onion3 != nullptr), "Onion failed initializing."); random_nonce(rng, nonce); ret = send_data_request(log3, onion3->net, rng, &path, &nodes[3].ip_port, dht_get_self_public_key(onion1->dht), dht_get_self_public_key(onion1->dht), nonce, (const uint8_t *)"Install gentoo", sizeof("Install gentoo")); ck_assert_msg(ret == 0, "Failed to create/send onion data_request packet."); handled_test_4 = 0; do { do_onion(mono_time1, onion1); do_onion(mono_time2, onion2); c_sleep(50); } while (handled_test_4 == 0); printf("test 4 complete\n"); kill_onion_announce(onion2_a); kill_onion_announce(onion1_a); { Onion *onion = onion3; Networking_Core *net = dht_get_net(onion->dht); DHT *dht = onion->dht; kill_onion(onion); kill_dht(dht); kill_networking(net); mono_time_free(mem, mono_time3); logger_kill(log3); } { Onion *onion = onion2; Networking_Core *net = dht_get_net(onion->dht); DHT *dht = onion->dht; kill_onion(onion); kill_dht(dht); kill_networking(net); mono_time_free(mem, mono_time2); logger_kill(log2); } { Onion *onion = onion1; Networking_Core *net = dht_get_net(onion->dht); DHT *dht = onion->dht; kill_onion(onion); kill_dht(dht); kill_networking(net); mono_time_free(mem, mono_time1); logger_kill(log1); } } typedef struct { Logger *log; Mono_Time *mono_time; Onion *onion; Onion_Announce *onion_a; Onion_Client *onion_c; } Onions; static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, uint32_t *index) { IP ip = get_loopback(); ip.ip.v6.uint8[15] = 1; const Network *ns = os_network(); Onions *on = (Onions *)malloc(sizeof(Onions)); if (!on) { return nullptr; } on->log = logger_new(); if (!on->log) { free(on); return nullptr; } logger_callback_log(on->log, print_debug_logger, nullptr, index); on->mono_time = mono_time_new(mem, nullptr, nullptr); if (!on->mono_time) { logger_kill(on->log); free(on); return nullptr; } Networking_Core *net = new_networking(on->log, mem, ns, &ip, port); if (!net) { mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); return nullptr; } DHT *dht = new_dht(on->log, mem, rng, ns, on->mono_time, net, true, false); if (!dht) { kill_networking(net); mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); return nullptr; } on->onion = new_onion(on->log, mem, on->mono_time, rng, dht); if (!on->onion) { kill_dht(dht); kill_networking(net); mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); return nullptr; } on->onion_a = new_onion_announce(on->log, mem, rng, on->mono_time, dht); if (!on->onion_a) { kill_onion(on->onion); kill_dht(dht); kill_networking(net); mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); return nullptr; } TCP_Proxy_Info inf = {{{{0}}}}; on->onion_c = new_onion_client(on->log, mem, rng, on->mono_time, new_net_crypto(on->log, mem, rng, ns, on->mono_time, dht, &inf)); if (!on->onion_c) { kill_onion_announce(on->onion_a); kill_onion(on->onion); kill_dht(dht); kill_networking(net); mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); return nullptr; } return on; } static void do_onions(Onions *on) { mono_time_update(on->mono_time); networking_poll(on->onion->net, nullptr); do_dht(on->onion->dht); do_onion_client(on->onion_c); } static void kill_onions(const Memory *mem, Onions *on) { Networking_Core *net = dht_get_net(on->onion->dht); DHT *dht = on->onion->dht; Net_Crypto *c = onion_get_net_crypto(on->onion_c); kill_onion_client(on->onion_c); kill_onion_announce(on->onion_a); kill_onion(on->onion); kill_net_crypto(c); kill_dht(dht); kill_networking(net); mono_time_free(mem, on->mono_time); logger_kill(on->log); free(on); } #define NUM_ONIONS 50 #define NUM_FIRST 7 #define NUM_LAST 37 static bool first_ip, last_ip; static void dht_ip_callback(void *object, int32_t number, const IP_Port *ip_port) { if (NUM_FIRST == number) { first_ip = 1; return; } if (NUM_LAST == number) { last_ip = 1; return; } ck_abort_msg("Error."); } static bool first, last; static uint8_t first_dht_pk[CRYPTO_PUBLIC_KEY_SIZE]; static uint8_t last_dht_pk[CRYPTO_PUBLIC_KEY_SIZE]; static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key, void *userdata) { if ((NUM_FIRST == number && !first) || (NUM_LAST == number && !last)) { Onions *on = (Onions *)object; uint32_t token = 0; int ret = dht_addfriend(on->onion->dht, dht_public_key, &dht_ip_callback, object, number, &token); ck_assert_msg(ret == 0, "dht_addfriend() did not return 0"); ck_assert_msg(token == 1, "Count not 1, count is %u", token); if (NUM_FIRST == number && !first) { first = 1; if (memcmp(dht_public_key, last_dht_pk, CRYPTO_PUBLIC_KEY_SIZE) != 0) { ck_abort_msg("Error wrong dht key."); } return; } if (NUM_LAST == number && !last) { last = 1; if (memcmp(dht_public_key, first_dht_pk, CRYPTO_PUBLIC_KEY_SIZE) != 0) { ck_abort_msg("Error wrong dht key."); } return; } ck_abort_msg("Error."); } } static void test_announce(void) { uint32_t index[NUM_ONIONS]; Onions *onions[NUM_ONIONS]; const Random *rng = os_random(); ck_assert(rng != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); for (uint32_t i = 0; i < NUM_ONIONS; ++i) { index[i] = i + 1; onions[i] = new_onions(mem, rng, i + 36655, &index[i]); ck_assert_msg(onions[i] != nullptr, "Failed to create onions. %u", i); } IP ip = get_loopback(); for (uint32_t i = 3; i < NUM_ONIONS; ++i) { IP_Port ip_port = {ip, net_port(onions[i - 1]->onion->net)}; dht_bootstrap(onions[i]->onion->dht, &ip_port, dht_get_self_public_key(onions[i - 1]->onion->dht)); IP_Port ip_port1 = {ip, net_port(onions[i - 2]->onion->net)}; dht_bootstrap(onions[i]->onion->dht, &ip_port1, dht_get_self_public_key(onions[i - 2]->onion->dht)); IP_Port ip_port2 = {ip, net_port(onions[i - 3]->onion->net)}; dht_bootstrap(onions[i]->onion->dht, &ip_port2, dht_get_self_public_key(onions[i - 3]->onion->dht)); } uint32_t connected = 0; do { connected = 0; for (uint32_t i = 0; i < NUM_ONIONS; ++i) { do_onions(onions[i]); connected += dht_isconnected(onions[i]->onion->dht); } c_sleep(50); } while (connected != NUM_ONIONS); printf("connected\n"); for (uint32_t i = 0; i < 25 * 2; ++i) { for (uint32_t j = 0; j < NUM_ONIONS; ++j) { do_onions(onions[j]); } c_sleep(50); } memcpy(first_dht_pk, dht_get_self_public_key(onions[NUM_FIRST]->onion->dht), CRYPTO_PUBLIC_KEY_SIZE); memcpy(last_dht_pk, dht_get_self_public_key(onions[NUM_LAST]->onion->dht), CRYPTO_PUBLIC_KEY_SIZE); printf("adding friend\n"); int frnum_f = onion_addfriend(onions[NUM_FIRST]->onion_c, nc_get_self_public_key(onion_get_net_crypto(onions[NUM_LAST]->onion_c))); int frnum = onion_addfriend(onions[NUM_LAST]->onion_c, nc_get_self_public_key(onion_get_net_crypto(onions[NUM_FIRST]->onion_c))); onion_dht_pk_callback(onions[NUM_FIRST]->onion_c, frnum_f, &dht_pk_callback, onions[NUM_FIRST], NUM_FIRST); onion_dht_pk_callback(onions[NUM_LAST]->onion_c, frnum, &dht_pk_callback, onions[NUM_LAST], NUM_LAST); IP_Port ip_port; do { for (uint32_t i = 0; i < NUM_ONIONS; ++i) { do_onions(onions[i]); } c_sleep(50); } while (!first || !last); printf("Waiting for ips\n"); do { for (uint32_t i = 0; i < NUM_ONIONS; ++i) { do_onions(onions[i]); } c_sleep(50); } while (!first_ip || !last_ip); onion_getfriendip(onions[NUM_LAST]->onion_c, frnum, &ip_port); ck_assert_msg(ip_port.port == net_port(onions[NUM_FIRST]->onion->net), "Port in returned ip not correct."); for (uint32_t i = 0; i < NUM_ONIONS; ++i) { kill_onions(mem, onions[i]); } } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_basic(); test_announce(); return 0; } c-toxcore-0.2.20/auto_tests/overflow_recvq_test.c0000644060175106017510000000435514714247532020146 0ustar robin/* Try to overflow the net_crypto packet buffer. */ #include typedef struct State { uint32_t recv_count; } State; #include "auto_test_support.h" #define NUM_MSGS 40000 static void handle_friend_message(const Tox_Event_Friend_Message *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_message_get_friend_number(event); //const Tox_Message_Type type = tox_event_friend_message_get_type(event); //const uint8_t *message = tox_event_friend_message_get_message(event); //const uint32_t message_length = tox_event_friend_message_get_message_length(event); const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; state->recv_count++; } static void net_crypto_overflow_test(AutoTox *autotoxes) { tox_events_callback_friend_message(autotoxes[0].dispatch, handle_friend_message); printf("sending many messages to tox0\n"); for (uint32_t tox_index = 1; tox_index < 3; tox_index++) { for (uint32_t i = 0; i < NUM_MSGS; i++) { uint8_t message[128] = {0}; snprintf((char *)message, sizeof(message), "%u-%u", tox_index, i); Tox_Err_Friend_Send_Message err; tox_friend_send_message(autotoxes[tox_index].tox, 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err); if (err == TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ) { printf("tox%u sent %u messages to friend 0\n", tox_index, i); break; } ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK, "tox%u failed to send message number %u: %d", tox_index, i, err); } } // TODO(iphydf): Wait until all messages have arrived. Currently, not all // messages arrive, so this test would always fail. for (uint32_t i = 0; i < 200; i++) { iterate_all_wait(autotoxes, 3, ITERATION_INTERVAL); } printf("tox%u received %u messages\n", autotoxes[0].index, ((State *)autotoxes[0].state)->recv_count); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 3, net_crypto_overflow_test, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/overflow_sendq_test.c0000644060175106017510000000250214714247532020130 0ustar robin/* Try to overflow the net_crypto packet buffer. */ #include #include "auto_test_support.h" #define NUM_MSGS 40000 static void net_crypto_overflow_test(AutoTox *autotoxes) { const uint8_t message[] = {0}; bool errored = false; for (uint32_t i = 0; i < NUM_MSGS; i++) { Tox_Err_Friend_Send_Message err; tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof message, &err); if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK) { errored = true; } if (errored) { // As soon as we get the first error, we expect the same error (SENDQ) // every time we try to send. ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ, "expected SENDQ error on message %u, but got %d", i, err); } else { ck_assert_msg(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK, "failed to send message number %u: %d", i, err); } } ck_assert_msg(errored, "expected SENDQ error at some point (increase NUM_MSGS?)"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, net_crypto_overflow_test, 0, &options); return 0; } c-toxcore-0.2.20/auto_tests/proxy_test.c0000644060175106017510000001033614714247532016260 0ustar robin/* Tests that we can send messages to friends. */ #include #include #include #include "auto_test_support.h" static void *proxy_routine(void *arg) { const char *proxy_bin = (const char *)arg; ck_assert(proxy_bin != nullptr); printf("starting http/sock5 proxy: %s\n", proxy_bin); ck_assert(system(proxy_bin) == 0); return nullptr; } static bool try_bootstrap(Tox *tox1, Tox *tox2, Tox *tox3, Tox *tox4) { for (uint32_t i = 0; i < 400; ++i) { if (tox_self_get_connection_status(tox1) != TOX_CONNECTION_NONE && tox_self_get_connection_status(tox2) != TOX_CONNECTION_NONE && tox_self_get_connection_status(tox3) != TOX_CONNECTION_NONE && tox_self_get_connection_status(tox4) != TOX_CONNECTION_NONE) { printf("%d %d %d %d\n", tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2), tox_self_get_connection_status(tox3), tox_self_get_connection_status(tox4)); return true; } tox_iterate(tox1, nullptr); tox_iterate(tox2, nullptr); tox_iterate(tox3, nullptr); tox_iterate(tox4, nullptr); if (i % 10 == 0) { printf("%d %d %d %d\n", tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2), tox_self_get_connection_status(tox3), tox_self_get_connection_status(tox4)); } c_sleep(tox_iteration_interval(tox1)); } return false; } int main(int argc, char **argv) { setvbuf(stdout, nullptr, _IONBF, 0); if (argc >= 3) { char *proxy_bin = argv[2]; pthread_t proxy_thread; pthread_create(&proxy_thread, nullptr, proxy_routine, proxy_bin); c_sleep(100); } const uint16_t tcp_port = 8082; uint32_t index[] = { 1, 2, 3, 4 }; struct Tox_Options *tox_options = tox_options_new(nullptr); ck_assert(tox_options != nullptr); // tox1 is a TCP server and has UDP enabled. tox_options_set_udp_enabled(tox_options, true); tox_options_set_tcp_port(tox_options, tcp_port); Tox *tox1 = tox_new_log(tox_options, nullptr, &index[0]); ck_assert(tox1 != nullptr); // Get tox1's DHT key and port. uint8_t dht_pk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_pk); uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); ck_assert(dht_port != 0); // tox2 is a regular DHT node bootstrapping against tox1. tox_options_set_udp_enabled(tox_options, true); tox_options_set_tcp_port(tox_options, 0); Tox *tox2 = tox_new_log(tox_options, nullptr, &index[1]); ck_assert(tox2 != nullptr); // tox2 bootstraps against tox1 with UDP. ck_assert(tox_bootstrap(tox2, "127.0.0.1", dht_port, dht_pk, nullptr)); // tox3 has UDP disabled and connects to tox1 via an HTTP proxy tox_options_set_udp_enabled(tox_options, false); tox_options_set_proxy_host(tox_options, "127.0.0.1"); tox_options_set_proxy_port(tox_options, 8080); tox_options_set_proxy_type(tox_options, TOX_PROXY_TYPE_HTTP); Tox *tox3 = tox_new_log(tox_options, nullptr, &index[2]); ck_assert(tox3 != nullptr); // tox4 has UDP disabled and connects to tox1 via a SOCKS5 proxy tox_options_set_udp_enabled(tox_options, false); tox_options_set_proxy_host(tox_options, "127.0.0.1"); tox_options_set_proxy_port(tox_options, 8081); tox_options_set_proxy_type(tox_options, TOX_PROXY_TYPE_SOCKS5); Tox *tox4 = tox_new_log(tox_options, nullptr, &index[3]); ck_assert(tox4 != nullptr); // tox3 and tox4 bootstrap against tox1 and add it as a TCP relay ck_assert(tox_bootstrap(tox3, "127.0.0.1", dht_port, dht_pk, nullptr)); ck_assert(tox_add_tcp_relay(tox3, "127.0.0.1", tcp_port, dht_pk, nullptr)); ck_assert(tox_bootstrap(tox4, "127.0.0.1", dht_port, dht_pk, nullptr)); ck_assert(tox_add_tcp_relay(tox4, "127.0.0.1", tcp_port, dht_pk, nullptr)); int ret = 1; if (try_bootstrap(tox1, tox2, tox3, tox4)) { ret = 0; } tox_options_free(tox_options); tox_kill(tox4); tox_kill(tox3); tox_kill(tox2); tox_kill(tox1); return ret; } c-toxcore-0.2.20/auto_tests/reconnect_test.c0000644060175106017510000000627614714247532017067 0ustar robin/* Auto Tests: Reconnection. * * This test checks that when a tox instance is suspended for long enough that * its friend connections time out, those connections are promptly * re-established when the instance is resumed. */ #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/friend_connection.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "check_compat.h" #define TOX_COUNT 2 #define RECONNECT_TIME_MAX (FRIEND_CONNECTION_TIMEOUT + 3) #include "auto_test_support.h" static uint32_t tox_connected_count(uint32_t tox_count, AutoTox *autotoxes, uint32_t index) { const size_t friend_count = tox_self_get_friend_list_size(autotoxes[index].tox); uint32_t connected_count = 0; for (size_t j = 0; j < friend_count; j++) { if (tox_friend_get_connection_status(autotoxes[index].tox, j, nullptr) != TOX_CONNECTION_NONE) { ++connected_count; } } return connected_count; } static bool all_disconnected_from(uint32_t tox_count, AutoTox *autotoxes, uint32_t index) { for (uint32_t i = 0; i < tox_count; i++) { if (i == index) { continue; } if (tox_connected_count(tox_count, autotoxes, i) >= tox_count - 1) { return false; } } return true; } static void test_reconnect(AutoTox *autotoxes) { const Random *rng = os_random(); ck_assert(rng != nullptr); const time_t test_start_time = time(nullptr); printf("letting connections settle\n"); do { iterate_all_wait(autotoxes, TOX_COUNT, ITERATION_INTERVAL); } while (time(nullptr) - test_start_time < 2); const uint16_t disconnect = random_u16(rng) % TOX_COUNT; printf("disconnecting #%u\n", autotoxes[disconnect].index); do { for (uint16_t i = 0; i < TOX_COUNT; ++i) { if (i != disconnect) { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(autotoxes[i].tox, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(autotoxes[i].dispatch, events, &autotoxes[i]); tox_events_free(events); autotoxes[i].clock += 1000; } } c_sleep(20); } while (!all_disconnected_from(TOX_COUNT, autotoxes, disconnect)); const uint64_t reconnect_start_time = autotoxes[0].clock; printf("reconnecting\n"); do { iterate_all_wait(autotoxes, TOX_COUNT, ITERATION_INTERVAL); } while (!all_friends_connected(autotoxes, TOX_COUNT)); const uint64_t reconnect_time = autotoxes[0].clock - reconnect_start_time; ck_assert_msg(reconnect_time <= RECONNECT_TIME_MAX * 1000, "reconnection took %d seconds; expected at most %d seconds", (int)(reconnect_time / 1000), RECONNECT_TIME_MAX); printf("test_reconnect succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time)); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, TOX_COUNT, test_reconnect, 0, &options); return 0; } c-toxcore-0.2.20/auto_tests/save_compatibility_test.c0000644060175106017510000001267414714247532020775 0ustar robin// Tests to make sure new save code is compatible with old save files #include "../testing/misc_tools.h" #include "../toxcore/tox.h" #include "auto_test_support.h" #include "check_compat.h" #include #include #include #define LOADED_SAVE_FILE_BIG "../auto_tests/data/save.tox.big" #define LOADED_SAVE_FILE_LITTLE "../auto_tests/data/save.tox.little" // Information from the save file #define EXPECTED_NAME "name" #define EXPECTED_NAME_SIZE strlen(EXPECTED_NAME) #define EXPECTED_STATUS_MESSAGE "Hello World" #define EXPECTED_STATUS_MESSAGE_SIZE strlen(EXPECTED_STATUS_MESSAGE) #define EXPECTED_NUM_FRIENDS 1 #define EXPECTED_NOSPAM "4C762C7D" #define EXPECTED_TOX_ID "E776E9A993EE3CAE04F5946D9AC66FBBAA8C63A95A94B41942353C6DC1739B4B4C762C7DA7B9" static size_t get_file_size(const char *save_path) { FILE *const fp = fopen(save_path, "rb"); if (fp == nullptr) { return 0; } fseek(fp, 0, SEEK_END); const size_t size = ftell(fp); fclose(fp); return size; } static uint8_t *read_save(const char *save_path, size_t *length) { const size_t size = get_file_size(save_path); if (size == 0) { return nullptr; } FILE *const fp = fopen(save_path, "rb"); if (!fp) { return nullptr; } uint8_t *const data = (uint8_t *)malloc(size); if (!data) { fclose(fp); return nullptr; } if (fread(data, size, 1, fp) != 1) { free(data); fclose(fp); return nullptr; } *length = size; fclose(fp); return data; } static void test_save_compatibility(const char *save_path) { struct Tox_Options options = {0}; tox_options_default(&options); size_t size = 0; uint8_t *save_data = read_save(save_path, &size); ck_assert_msg(save_data != nullptr, "error while reading save file '%s'", save_path); options.savedata_data = save_data; options.savedata_length = size; options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE; size_t index = 0; Tox_Err_New err; Tox *tox = tox_new_log(&options, &err, &index); ck_assert_msg(tox, "failed to create tox, error number: %d", err); free(save_data); const size_t name_size = tox_self_get_name_size(tox); ck_assert_msg(name_size == EXPECTED_NAME_SIZE, "name sizes do not match expected %zu got %zu", EXPECTED_NAME_SIZE, name_size); uint8_t *name = (uint8_t *)malloc(tox_self_get_name_size(tox)); ck_assert(name != nullptr); tox_self_get_name(tox, name); ck_assert_msg(strncmp((const char *)name, EXPECTED_NAME, name_size) == 0, "names do not match, expected %s got %s", EXPECTED_NAME, name); const size_t status_message_size = tox_self_get_status_message_size(tox); ck_assert_msg(status_message_size == EXPECTED_STATUS_MESSAGE_SIZE, "status message sizes do not match, expected %zu got %zu", EXPECTED_STATUS_MESSAGE_SIZE, status_message_size); uint8_t *status_message = (uint8_t *)malloc(tox_self_get_status_message_size(tox)); ck_assert(status_message != nullptr); tox_self_get_status_message(tox, status_message); ck_assert_msg(strncmp((const char *)status_message, EXPECTED_STATUS_MESSAGE, status_message_size) == 0, "status messages do not match, expected %s got %s", EXPECTED_STATUS_MESSAGE, status_message); const size_t num_friends = tox_self_get_friend_list_size(tox); ck_assert_msg(num_friends == EXPECTED_NUM_FRIENDS, "number of friends do not match, expected %d got %zu", EXPECTED_NUM_FRIENDS, num_friends); const uint32_t nospam = tox_self_get_nospam(tox); char nospam_str[TOX_NOSPAM_SIZE * 2 + 1]; const size_t length = snprintf(nospam_str, sizeof(nospam_str), "%08X", nospam); nospam_str[length] = '\0'; ck_assert_msg(strcmp(nospam_str, EXPECTED_NOSPAM) == 0, "nospam does not match, expected %s got %s", EXPECTED_NOSPAM, nospam_str); uint8_t tox_id[TOX_ADDRESS_SIZE]; char tox_id_str[TOX_ADDRESS_SIZE * 2 + 1] = {0}; tox_self_get_address(tox, tox_id); to_hex(tox_id_str, tox_id, TOX_ADDRESS_SIZE); ck_assert_msg(strncmp(tox_id_str, EXPECTED_TOX_ID, TOX_ADDRESS_SIZE * 2) == 0, "tox ids do not match, expected %s got %s", EXPECTED_TOX_ID, tox_id_str); /* Giving the tox a chance to error on iterate due to corrupted loaded structures */ tox_iterate(tox, nullptr); free(status_message); free(name); tox_kill(tox); } static bool is_little_endian(void) { uint16_t x = 1; return ((uint8_t *)&x)[0] == 1; } // cppcheck-suppress constParameter int main(int argc, char *argv[]) { char base_path[4096] = {0}; if (argc <= 1) { const char *srcdir = getenv("srcdir"); if (srcdir == nullptr) { srcdir = "."; } snprintf(base_path, sizeof(base_path), "%s", srcdir); } else { snprintf(base_path, sizeof(base_path), "%s", argv[1]); base_path[strrchr(base_path, '/') - base_path] = '\0'; } if (is_little_endian()) { char save_path[4096 + sizeof(LOADED_SAVE_FILE_LITTLE)]; snprintf(save_path, sizeof(save_path), "%s/%s", base_path, LOADED_SAVE_FILE_LITTLE); test_save_compatibility(save_path); } else { char save_path[4096 + sizeof(LOADED_SAVE_FILE_BIG)]; snprintf(save_path, sizeof(save_path), "%s/%s", base_path, LOADED_SAVE_FILE_BIG); test_save_compatibility(save_path); } return 0; } c-toxcore-0.2.20/auto_tests/save_friend_test.c0000644060175106017510000001447414714247532017373 0ustar robin/* Auto Tests: Save and load friends. */ #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/crypto_core.h" #include "../toxcore/tox.h" #include "auto_test_support.h" #include "check_compat.h" struct test_data { uint8_t *name; uint8_t *status_message; bool received_name; bool received_status_message; }; static void set_random(Tox *m, const Random *rng, bool (*setter)(Tox *, const uint8_t *, size_t, Tox_Err_Set_Info *), size_t length) { VLA(uint8_t, text, length); for (uint32_t i = 0; i < length; ++i) { text[i] = random_u08(rng); } setter(m, text, length, nullptr); } static void alloc_string(uint8_t **to, size_t length) { free(*to); *to = (uint8_t *)malloc(length); ck_assert(*to != nullptr); } static void set_string(uint8_t **to, const uint8_t *from, size_t length) { alloc_string(to, length); memcpy(*to, from, length); } static void namechange_callback(const Tox_Event_Friend_Name *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_name_get_friend_number(event); const uint8_t *name = tox_event_friend_name_get_name(event); const uint32_t name_length = tox_event_friend_name_get_name_length(event); struct test_data *to_compare = (struct test_data *)user_data; set_string(&to_compare->name, name, name_length); to_compare->received_name = true; } static void statuschange_callback(const Tox_Event_Friend_Status_Message *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_status_message_get_friend_number(event); const uint8_t *message = tox_event_friend_status_message_get_message(event); const uint32_t message_length = tox_event_friend_status_message_get_message_length(event); struct test_data *to_compare = (struct test_data *)user_data; set_string(&to_compare->status_message, message, message_length); to_compare->received_status_message = true; } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Tox *const tox1 = tox_new_log(nullptr, nullptr, nullptr); Tox *const tox2 = tox_new_log(nullptr, nullptr, nullptr); ck_assert(tox1 != nullptr); ck_assert(tox2 != nullptr); tox_events_init(tox1); Tox_Dispatch *dispatch1 = tox_dispatch_new(nullptr); ck_assert(dispatch1 != nullptr); printf("bootstrapping tox2 off tox1\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr); struct test_data to_compare = {nullptr}; uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(tox1, public_key); tox_friend_add_norequest(tox2, public_key, nullptr); tox_self_get_public_key(tox2, public_key); tox_friend_add_norequest(tox1, public_key, nullptr); uint8_t *reference_name = (uint8_t *)malloc(tox_max_name_length()); uint8_t *reference_status = (uint8_t *)malloc(tox_max_status_message_length()); ck_assert(reference_name != nullptr); ck_assert(reference_status != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); set_random(tox1, rng, tox_self_set_name, tox_max_name_length()); set_random(tox2, rng, tox_self_set_name, tox_max_name_length()); set_random(tox1, rng, tox_self_set_status_message, tox_max_status_message_length()); set_random(tox2, rng, tox_self_set_status_message, tox_max_status_message_length()); tox_self_get_name(tox2, reference_name); tox_self_get_status_message(tox2, reference_status); tox_events_callback_friend_name(dispatch1, namechange_callback); tox_events_callback_friend_status_message(dispatch1, statuschange_callback); while (true) { if (tox_self_get_connection_status(tox1) && tox_self_get_connection_status(tox2) && tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_UDP) { printf("Connected.\n"); break; } Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch1, events, &to_compare); tox_events_free(events); tox_iterate(tox2, nullptr); c_sleep(tox_iteration_interval(tox1)); } while (true) { if (to_compare.received_name && to_compare.received_status_message) { printf("Exchanged names and status messages.\n"); break; } Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch1, events, &to_compare); tox_events_free(events); tox_iterate(tox2, nullptr); c_sleep(tox_iteration_interval(tox1)); } size_t save_size = tox_get_savedata_size(tox1); uint8_t *savedata = (uint8_t *)malloc(save_size); tox_get_savedata(tox1, savedata); struct Tox_Options *const options = tox_options_new(nullptr); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, savedata, save_size); Tox *const tox_to_compare = tox_new_log(options, nullptr, nullptr); alloc_string(&to_compare.name, tox_friend_get_name_size(tox_to_compare, 0, nullptr)); tox_friend_get_name(tox_to_compare, 0, to_compare.name, nullptr); alloc_string(&to_compare.status_message, tox_friend_get_status_message_size(tox_to_compare, 0, nullptr)); tox_friend_get_status_message(tox_to_compare, 0, to_compare.status_message, nullptr); ck_assert_msg(memcmp(reference_name, to_compare.name, tox_max_name_length()) == 0, "incorrect name: should be all zeroes"); ck_assert_msg(memcmp(reference_status, to_compare.status_message, tox_max_status_message_length()) == 0, "incorrect status message: should be all zeroes"); tox_options_free(options); tox_dispatch_free(dispatch1); tox_kill(tox1); tox_kill(tox2); tox_kill(tox_to_compare); free(savedata); free(to_compare.name); free(to_compare.status_message); free(reference_status); free(reference_name); return 0; } c-toxcore-0.2.20/auto_tests/save_load_test.c0000644060175106017510000002525014714247532017035 0ustar robin/* Tests that we can save and load Tox data. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/tox_struct.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif #ifdef TOX_LOCALHOST #undef TOX_LOCALHOST #endif #if USE_IPV6 #define TOX_LOCALHOST "::1" #else #define TOX_LOCALHOST "127.0.0.1" #endif #ifdef TCP_RELAY_PORT #undef TCP_RELAY_PORT #endif #define TCP_RELAY_PORT 33431 static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { Tox *tox = (Tox *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *message = tox_event_friend_request_get_message(event); uint32_t message_length = tox_event_friend_request_get_message_length(event); if (message_length == 7 && memcmp("Gentoo", message, 7) == 0) { tox_friend_add_norequest(tox, public_key, nullptr); } } static unsigned int connected_t1; static void tox_connection_status(const Tox_Event_Self_Connection_Status *event, void *user_data) { const Tox_Connection connection_status = tox_event_self_connection_status_get_connection_status(event); if (connected_t1 && !connection_status) { ck_abort_msg("Tox went offline"); } ck_assert_msg(connection_status != TOX_CONNECTION_NONE, "wrong status %d", connection_status); connected_t1 = connection_status; } /* validate that: * a) saving stays within the confined space * b) a saved state can be loaded back successfully * c) a second save is of equal size * d) the second save is of equal content */ static void reload_tox(Tox **tox, struct Tox_Options *const in_opts, void *user_data) { const size_t extra = 64; const size_t save_size1 = tox_get_savedata_size(*tox); ck_assert_msg(save_size1 != 0, "save is invalid size %u", (unsigned)save_size1); printf("%u\n", (unsigned)save_size1); uint8_t *buffer = (uint8_t *)malloc(save_size1 + 2 * extra); ck_assert_msg(buffer != nullptr, "malloc failed"); memset(buffer, 0xCD, extra); memset(buffer + extra + save_size1, 0xCD, extra); tox_get_savedata(*tox, buffer + extra); tox_kill(*tox); for (size_t i = 0; i < extra; ++i) { ck_assert_msg(buffer[i] == 0xCD, "Buffer underwritten from tox_get_savedata() @%u", (unsigned)i); ck_assert_msg(buffer[extra + save_size1 + i] == 0xCD, "Buffer overwritten from tox_get_savedata() @%u", (unsigned)i); } struct Tox_Options *const options = (in_opts == nullptr) ? tox_options_new(nullptr) : in_opts; tox_options_set_ipv6_enabled(options, USE_IPV6); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, buffer + extra, save_size1); *tox = tox_new_log(options, nullptr, user_data); if (in_opts == nullptr) { tox_options_free(options); } ck_assert_msg(*tox != nullptr, "Failed to load back stored buffer"); const size_t save_size2 = tox_get_savedata_size(*tox); ck_assert_msg(save_size1 == save_size2, "Tox save data changed in size from a store/load cycle: %u -> %u", (unsigned)save_size1, (unsigned)save_size2); uint8_t *buffer2 = (uint8_t *)malloc(save_size2); ck_assert_msg(buffer2 != nullptr, "malloc failed"); tox_get_savedata(*tox, buffer2); ck_assert_msg(!memcmp(buffer + extra, buffer2, save_size2), "Tox state changed by store/load/store cycle"); free(buffer2); free(buffer); } typedef struct Time_Data { pthread_mutex_t lock; uint64_t clock; } Time_Data; static uint64_t get_state_clock_callback(void *user_data) { Time_Data *time_data = (Time_Data *)user_data; pthread_mutex_lock(&time_data->lock); uint64_t clock = time_data->clock; pthread_mutex_unlock(&time_data->lock); return clock; } static void increment_clock(Time_Data *time_data, uint64_t count) { pthread_mutex_lock(&time_data->lock); time_data->clock += count; pthread_mutex_unlock(&time_data->lock); } static void set_current_time_callback(Tox *tox, Time_Data *time_data) { Mono_Time *mono_time = tox->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data); } static void test_few_clients(void) { uint32_t index[] = { 1, 2, 3 }; time_t con_time = 0, cur_time = time(nullptr); struct Tox_Options *opts1 = tox_options_new(nullptr); tox_options_set_ipv6_enabled(opts1, USE_IPV6); tox_options_set_tcp_port(opts1, TCP_RELAY_PORT); Tox_Err_New t_n_error; Tox *tox1 = tox_new_log(opts1, &t_n_error, &index[0]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "Failed to create tox instance: %d", t_n_error); tox_options_free(opts1); tox_events_init(tox1); Tox_Dispatch *dispatch1 = tox_dispatch_new(nullptr); ck_assert(dispatch1 != nullptr); struct Tox_Options *opts2 = tox_options_new(nullptr); tox_options_set_ipv6_enabled(opts2, USE_IPV6); tox_options_set_udp_enabled(opts2, false); tox_options_set_local_discovery_enabled(opts2, false); Tox *tox2 = tox_new_log(opts2, &t_n_error, &index[1]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "Failed to create tox instance: %d", t_n_error); tox_events_init(tox2); Tox_Dispatch *dispatch2 = tox_dispatch_new(nullptr); ck_assert(dispatch2 != nullptr); struct Tox_Options *opts3 = tox_options_new(nullptr); tox_options_set_ipv6_enabled(opts3, USE_IPV6); tox_options_set_local_discovery_enabled(opts3, false); Tox *tox3 = tox_new_log(opts3, &t_n_error, &index[2]); ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, "Failed to create tox instance: %d", t_n_error); ck_assert_msg(tox1 && tox2 && tox3, "Failed to create 3 tox instances"); Time_Data time_data; ck_assert_msg(pthread_mutex_init(&time_data.lock, nullptr) == 0, "Failed to init time_data mutex"); time_data.clock = current_time_monotonic(tox1->mono_time); set_current_time_callback(tox1, &time_data); set_current_time_callback(tox2, &time_data); set_current_time_callback(tox3, &time_data); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); printf("using tox1 as tcp relay for tox2\n"); tox_add_tcp_relay(tox2, TOX_LOCALHOST, TCP_RELAY_PORT, dht_key, nullptr); printf("bootstrapping toxes off tox1\n"); tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr); tox_bootstrap(tox3, "localhost", dht_port, dht_key, nullptr); connected_t1 = 0; tox_events_callback_self_connection_status(dispatch1, tox_connection_status); tox_events_callback_friend_request(dispatch2, accept_friend_request); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); uint32_t test = tox_friend_add(tox3, address, (const uint8_t *)"Gentoo", 7, nullptr); ck_assert_msg(test == 0, "Failed to add friend error code: %u", test); uint8_t off = 1; while (true) { { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch1, events, tox1); tox_events_free(events); } { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch2, events, tox2); tox_events_free(events); } tox_iterate(tox3, nullptr); if (tox_self_get_connection_status(tox1) && tox_self_get_connection_status(tox2) && tox_self_get_connection_status(tox3)) { if (off) { printf("Toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); con_time = time(nullptr); off = 0; } if (tox_friend_get_connection_status(tox2, 0, nullptr) == TOX_CONNECTION_TCP && tox_friend_get_connection_status(tox3, 0, nullptr) == TOX_CONNECTION_TCP) { break; } } increment_clock(&time_data, 200); c_sleep(5); } ck_assert_msg(connected_t1, "Tox1 isn't connected. %u", connected_t1); printf("tox clients connected took %lu seconds\n", (unsigned long)(time(nullptr) - con_time)); // We're done with this callback, so unset it to ensure we don't fail the // test if tox1 goes offline while tox2 and 3 are reloaded. tox_events_callback_self_connection_status(dispatch1, nullptr); reload_tox(&tox2, opts2, &index[1]); tox_events_init(tox2); reload_tox(&tox3, opts3, &index[2]); cur_time = time(nullptr); off = 1; while (true) { { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch1, events, tox1); tox_events_free(events); } { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch2, events, tox2); tox_events_free(events); } tox_iterate(tox3, nullptr); if (tox_self_get_connection_status(tox1) && tox_self_get_connection_status(tox2) && tox_self_get_connection_status(tox3)) { if (off) { printf("Toxes are online again after reloading, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); con_time = time(nullptr); off = 0; } if (tox_friend_get_connection_status(tox2, 0, nullptr) == TOX_CONNECTION_TCP && tox_friend_get_connection_status(tox3, 0, nullptr) == TOX_CONNECTION_TCP) { break; } } increment_clock(&time_data, 100); c_sleep(5); } printf("tox clients connected took %lu seconds\n", (unsigned long)(time(nullptr) - con_time)); printf("test_few_clients succeeded, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); tox_dispatch_free(dispatch1); tox_dispatch_free(dispatch2); tox_kill(tox1); tox_kill(tox2); tox_kill(tox3); tox_options_free(opts2); tox_options_free(opts3); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_few_clients(); return 0; } c-toxcore-0.2.20/auto_tests/send_message_test.c0000644060175106017510000000510514714247532017532 0ustar robin/* Tests that we can send messages to friends. */ #include #include #include typedef struct State { bool message_received; } State; #include "auto_test_support.h" #define MESSAGE_FILLER 'G' static void message_callback( const Tox_Event_Friend_Message *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; const Tox_Message_Type type = tox_event_friend_message_get_type(event); const uint8_t *string = tox_event_friend_message_get_message(event); const uint32_t length = tox_event_friend_message_get_message_length(event); if (type != TOX_MESSAGE_TYPE_NORMAL) { ck_abort_msg("Bad type"); } const size_t cmp_msg_len = tox_max_message_length(); uint8_t *cmp_msg = (uint8_t *)malloc(cmp_msg_len); ck_assert(cmp_msg != nullptr); memset(cmp_msg, MESSAGE_FILLER, cmp_msg_len); if (length == tox_max_message_length() && memcmp(string, cmp_msg, cmp_msg_len) == 0) { state->message_received = true; } free(cmp_msg); } static void send_message_test(AutoTox *autotoxes) { tox_events_callback_friend_message(autotoxes[1].dispatch, &message_callback); const size_t msgs_len = tox_max_message_length() + 1; uint8_t *msgs = (uint8_t *)malloc(msgs_len); ck_assert(msgs != nullptr); memset(msgs, MESSAGE_FILLER, msgs_len); Tox_Err_Friend_Send_Message errm; tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, msgs_len, &errm); ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG, "tox_max_message_length() is too small? error=%d", errm); tox_friend_send_message(autotoxes[0].tox, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, tox_max_message_length(), &errm); ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_OK, "tox_max_message_length() is too big? error=%d", errm); free(msgs); do { iterate_all_wait(autotoxes, 2, ITERATION_INTERVAL); } while (!((State *)autotoxes[1].state)->message_received); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); struct Tox_Options *tox_options = tox_options_new(nullptr); ck_assert(tox_options != nullptr); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; tox_options_set_ipv6_enabled(tox_options, true); run_auto_test(tox_options, 2, send_message_test, sizeof(State), &options); tox_options_set_ipv6_enabled(tox_options, false); run_auto_test(tox_options, 2, send_message_test, sizeof(State), &options); tox_options_free(tox_options); return 0; } c-toxcore-0.2.20/auto_tests/set_name_test.c0000644060175106017510000001111614714247532016667 0ustar robin/* Tests that we can set our name. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #define NICKNAME "Gentoo" static void nickchange_callback(const Tox_Event_Friend_Name *event, void *user_data) { //const uint32_t friend_number = tox_event_friend_name_get_friend_number(event); const uint8_t *name = tox_event_friend_name_get_name(event); const uint32_t name_length = tox_event_friend_name_get_name_length(event); ck_assert_msg(name_length == sizeof(NICKNAME), "Name length not correct: %d != %d", (uint16_t)name_length, (uint16_t)sizeof(NICKNAME)); ck_assert_msg(memcmp(name, NICKNAME, sizeof(NICKNAME)) == 0, "Name not correct: %s", (const char *)name); bool *nickname_updated = (bool *)user_data; *nickname_updated = true; } static void test_set_name(void) { printf("initialising 2 toxes\n"); uint32_t index[] = { 1, 2 }; const time_t cur_time = time(nullptr); Tox *const tox1 = tox_new_log(nullptr, nullptr, &index[0]); Tox *const tox2 = tox_new_log(nullptr, nullptr, &index[1]); ck_assert_msg(tox1 && tox2, "failed to create 2 tox instances"); // we only run events on tox2 in this test case tox_events_init(tox2); Tox_Dispatch *dispatch2 = tox_dispatch_new(nullptr); ck_assert(dispatch2 != nullptr); printf("tox1 adds tox2 as friend, tox2 adds tox1\n"); uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(tox2, public_key); tox_friend_add_norequest(tox1, public_key, nullptr); tox_self_get_public_key(tox1, public_key); tox_friend_add_norequest(tox2, public_key, nullptr); printf("bootstrapping tox2 off tox1\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr); do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); //tox_dispatch_invoke(dispatch2, events, nullptr); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE); printf("toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); const time_t con_time = time(nullptr); do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); //tox_dispatch_invoke(dispatch2, events, nullptr); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (tox_friend_get_connection_status(tox1, 0, nullptr) != TOX_CONNECTION_UDP || tox_friend_get_connection_status(tox2, 0, nullptr) != TOX_CONNECTION_UDP); printf("tox clients connected took %lu seconds\n", (unsigned long)(time(nullptr) - con_time)); tox_events_callback_friend_name(dispatch2, nickchange_callback); Tox_Err_Set_Info err_n; bool ret = tox_self_set_name(tox1, (const uint8_t *)NICKNAME, sizeof(NICKNAME), &err_n); ck_assert_msg(ret && err_n == TOX_ERR_SET_INFO_OK, "tox_self_set_name failed because %d\n", err_n); bool nickname_updated = false; do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch2, events, &nickname_updated); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (!nickname_updated); ck_assert_msg(tox_friend_get_name_size(tox2, 0, nullptr) == sizeof(NICKNAME), "Name length not correct"); uint8_t temp_name[sizeof(NICKNAME)]; tox_friend_get_name(tox2, 0, temp_name, nullptr); ck_assert_msg(memcmp(temp_name, NICKNAME, sizeof(NICKNAME)) == 0, "Name not correct"); printf("test_set_name succeeded, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); tox_dispatch_free(dispatch2); tox_kill(tox1); tox_kill(tox2); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_set_name(); return 0; } c-toxcore-0.2.20/auto_tests/set_status_message_test.c0000644060175106017510000001142214714247532020776 0ustar robin/* Tests that we can set our status message */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #define STATUS_MESSAGE "Installing Gentoo" static void status_callback(const Tox_Event_Friend_Status_Message *event, void *user_data) { //uint32_t friend_number = tox_event_friend_status_message_get_friend_number(event); const uint8_t *message = tox_event_friend_status_message_get_message(event); uint32_t message_length = tox_event_friend_status_message_get_message_length(event); ck_assert_msg(message_length == sizeof(STATUS_MESSAGE) && memcmp(message, STATUS_MESSAGE, sizeof(STATUS_MESSAGE)) == 0, "incorrect data in status callback"); bool *status_updated = (bool *)user_data; *status_updated = true; } static void test_set_status_message(void) { printf("initialising 2 toxes\n"); uint32_t index[] = { 1, 2 }; const time_t cur_time = time(nullptr); Tox *const tox1 = tox_new_log(nullptr, nullptr, &index[0]); Tox *const tox2 = tox_new_log(nullptr, nullptr, &index[1]); ck_assert_msg(tox1 && tox2, "failed to create 2 tox instances"); // we only run events on tox2 in this test case tox_events_init(tox2); Tox_Dispatch *dispatch2 = tox_dispatch_new(nullptr); ck_assert(dispatch2 != nullptr); printf("tox1 adds tox2 as friend, tox2 adds tox1\n"); uint8_t public_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_public_key(tox2, public_key); tox_friend_add_norequest(tox1, public_key, nullptr); tox_self_get_public_key(tox1, public_key); tox_friend_add_norequest(tox2, public_key, nullptr); printf("bootstrapping tox2 off tox1\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(tox1, dht_key); const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr); tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr); do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); //tox_dispatch_invoke(dispatch2, events, nullptr); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE); printf("toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); const time_t con_time = time(nullptr); do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); //tox_dispatch_invoke(dispatch2, events, nullptr); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (tox_friend_get_connection_status(tox1, 0, nullptr) != TOX_CONNECTION_UDP || tox_friend_get_connection_status(tox2, 0, nullptr) != TOX_CONNECTION_UDP); printf("tox clients connected took %lu seconds\n", (unsigned long)(time(nullptr) - con_time)); tox_events_callback_friend_status_message(dispatch2, status_callback); Tox_Err_Set_Info err_n; bool ret = tox_self_set_status_message(tox1, (const uint8_t *)STATUS_MESSAGE, sizeof(STATUS_MESSAGE), &err_n); ck_assert_msg(ret && err_n == TOX_ERR_SET_INFO_OK, "tox_self_set_status_message failed because %d\n", err_n); bool status_updated = false; do { tox_iterate(tox1, nullptr); Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch2, events, &status_updated); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } while (!status_updated); ck_assert_msg(tox_friend_get_status_message_size(tox2, 0, nullptr) == sizeof(STATUS_MESSAGE), "status message length not correct"); uint8_t cmp_status[sizeof(STATUS_MESSAGE)]; tox_friend_get_status_message(tox2, 0, cmp_status, nullptr); ck_assert_msg(memcmp(cmp_status, STATUS_MESSAGE, sizeof(STATUS_MESSAGE)) == 0, "status message not correct"); printf("test_set_status_message succeeded, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); tox_dispatch_free(dispatch2); tox_kill(tox1); tox_kill(tox2); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_set_status_message(); return 0; } c-toxcore-0.2.20/auto_tests/tcp_relay_test.c0000644060175106017510000000164614714247532017065 0ustar robin#include #include "../testing/misc_tools.h" #include "check_compat.h" #include "auto_test_support.h" int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); struct Tox_Options *opts = tox_options_new(nullptr); tox_options_set_udp_enabled(opts, false); Tox *tox_tcp = tox_new_log(opts, nullptr, nullptr); tox_options_free(opts); bootstrap_tox_live_network(tox_tcp, true); printf("Waiting for connection"); do { printf("."); fflush(stdout); tox_iterate(tox_tcp, nullptr); c_sleep(ITERATION_INTERVAL); } while (tox_self_get_connection_status(tox_tcp) == TOX_CONNECTION_NONE); const Tox_Connection status = tox_self_get_connection_status(tox_tcp); ck_assert_msg(status == TOX_CONNECTION_TCP, "expected TCP connection, but got %d", status); printf("Connection (TCP): %d\n", status); tox_kill(tox_tcp); return 0; } c-toxcore-0.2.20/auto_tests/TCP_test.c0000644060175106017510000011336614714247532015534 0ustar robin#include #include #include #include "../testing/misc_tools.h" #include "../toxcore/TCP_client.h" #include "../toxcore/TCP_common.h" #include "../toxcore/TCP_server.h" #include "../toxcore/crypto_core.h" #include "../toxcore/mono_time.h" #include "../toxcore/util.h" #include "auto_test_support.h" #define NUM_PORTS 3 #ifndef USE_IPV6 #define USE_IPV6 1 #endif #if !USE_IPV6 #define net_family_ipv6 net_family_ipv4 #endif static IP get_loopback(void) { IP ip; #if USE_IPV6 ip.family = net_family_ipv6(); ip.ip.v6 = get_ip6_loopback(); #else ip.family = net_family_ipv4(); ip.ip.v4 = get_ip4_loopback(); #endif return ip; } static void do_tcp_server_delay(TCP_Server *tcp_s, Mono_Time *mono_time, int delay) { c_sleep(delay); mono_time_update(mono_time); do_tcp_server(tcp_s, mono_time); c_sleep(delay); } static uint16_t ports[NUM_PORTS] = {13215, 33445, 25643}; static void test_basic(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Logger *logger = logger_new(); logger_callback_log(logger, print_debug_logger, nullptr, nullptr); // Attempt to create a new TCP_Server instance. uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Server *tcp_s = new_tcp_server(logger, mem, rng, ns, USE_IPV6, NUM_PORTS, ports, self_secret_key, nullptr, nullptr); ck_assert_msg(tcp_s != nullptr, "Failed to create a TCP relay server."); ck_assert_msg(tcp_server_listen_count(tcp_s) == NUM_PORTS, "Failed to bind a TCP relay server to all %d attempted ports.", NUM_PORTS); Socket sock = {0}; IP_Port localhost; localhost.ip = get_loopback(); localhost.port = 0; // Check all opened ports for connectivity. for (uint8_t i = 0; i < NUM_PORTS; i++) { sock = net_socket(ns, net_family_ipv6(), TOX_SOCK_STREAM, TOX_PROTO_TCP); localhost.port = net_htons(ports[i]); bool ret = net_connect(mem, logger, sock, &localhost); ck_assert_msg(ret, "Failed to connect to created TCP relay server on port %d (%d).", ports[i], errno); // Leave open one connection for the next test. if (i + 1 < NUM_PORTS) { kill_sock(ns, sock); } } // Key creation. uint8_t f_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t f_secret_key[CRYPTO_SECRET_KEY_SIZE]; uint8_t f_nonce[CRYPTO_NONCE_SIZE]; crypto_new_keypair(rng, f_public_key, f_secret_key); random_nonce(rng, f_nonce); // Generation of the initial handshake. uint8_t t_secret_key[CRYPTO_SECRET_KEY_SIZE]; uint8_t *handshake_plain = (uint8_t *)malloc(TCP_HANDSHAKE_PLAIN_SIZE); ck_assert(handshake_plain != nullptr); crypto_new_keypair(rng, handshake_plain, t_secret_key); memcpy(handshake_plain + CRYPTO_PUBLIC_KEY_SIZE, f_nonce, CRYPTO_NONCE_SIZE); uint8_t *handshake = (uint8_t *)malloc(TCP_CLIENT_HANDSHAKE_SIZE); ck_assert(handshake != nullptr); memcpy(handshake, f_public_key, CRYPTO_PUBLIC_KEY_SIZE); random_nonce(rng, handshake + CRYPTO_PUBLIC_KEY_SIZE); // Encrypting handshake int ret = encrypt_data(self_public_key, f_secret_key, handshake + CRYPTO_PUBLIC_KEY_SIZE, handshake_plain, TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), "encrypt_data() call failed."); free(handshake_plain); // Sending the handshake ck_assert_msg(net_send(ns, logger, sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, &localhost) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "An attempt to send the initial handshake minus last byte failed."); do_tcp_server_delay(tcp_s, mono_time, 50); ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost) == 1, "The attempt to send the last byte of handshake failed."); free(handshake); do_tcp_server_delay(tcp_s, mono_time, 50); // Receiving server response and decrypting it uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE]; ck_assert_msg(net_recv(ns, logger, sock, response, TCP_SERVER_HANDSHAKE_SIZE, &localhost) == TCP_SERVER_HANDSHAKE_SIZE, "Could/did not receive a server response to the initial handshake."); ret = decrypt_data(self_public_key, f_secret_key, response, response + CRYPTO_NONCE_SIZE, TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain); ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Failed to decrypt handshake response."); uint8_t f_nonce_r[CRYPTO_NONCE_SIZE]; uint8_t f_shared_key[CRYPTO_SHARED_KEY_SIZE]; encrypt_precompute(response_plain, t_secret_key, f_shared_key); memcpy(f_nonce_r, response_plain + CRYPTO_SHARED_KEY_SIZE, CRYPTO_NONCE_SIZE); // Building a request uint8_t r_req_p[1 + CRYPTO_PUBLIC_KEY_SIZE]; r_req_p[0] = TCP_PACKET_ROUTING_REQUEST; memcpy(r_req_p + 1, f_public_key, CRYPTO_PUBLIC_KEY_SIZE); uint8_t r_req[2 + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE]; uint16_t size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE; size = net_htons(size); encrypt_data_symmetric(f_shared_key, f_nonce, r_req_p, 1 + CRYPTO_PUBLIC_KEY_SIZE, r_req + 2); increment_nonce(f_nonce); memcpy(r_req, &size, 2); // Sending the request at random intervals in random pieces. for (uint32_t i = 0; i < sizeof(r_req);) { uint8_t msg_length = rand() % 5 + 1; // msg_length = 1 to 5 if (i + msg_length >= sizeof(r_req)) { msg_length = sizeof(r_req) - i; } ck_assert_msg(net_send(ns, logger, sock, r_req + i, msg_length, &localhost) == msg_length, "Failed to send request after completing the handshake."); i += msg_length; c_sleep(50); mono_time_update(mono_time); do_tcp_server(tcp_s, mono_time); } // Receiving the second response and verifying its validity uint8_t packet_resp[4096]; int recv_data_len = net_recv(ns, logger, sock, packet_resp, 2 + 2 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE, &localhost); ck_assert_msg(recv_data_len == 2 + 2 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE, "Failed to receive server response to request. %d", recv_data_len); memcpy(&size, packet_resp, 2); ck_assert_msg(net_ntohs(size) == 2 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE, "Wrong packet size for request response."); uint8_t packet_resp_plain[4096]; ret = decrypt_data_symmetric(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain); ck_assert_msg(ret != -1, "Failed to decrypt the TCP server's response."); increment_nonce(f_nonce_r); ck_assert_msg(packet_resp_plain[0] == TCP_PACKET_ROUTING_RESPONSE, "Server sent the wrong packet id: %u", packet_resp_plain[0]); ck_assert_msg(packet_resp_plain[1] == 0, "Server did not refuse the connection."); ck_assert_msg(pk_equal(packet_resp_plain + 2, f_public_key), "Server sent the wrong public key."); // Closing connections. kill_sock(ns, sock); kill_tcp_server(tcp_s); logger_kill(logger); mono_time_free(mem, mono_time); } struct sec_TCP_con { Socket sock; const Network *ns; const Memory *mem; uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; }; static struct sec_TCP_con *new_tcp_con(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns, TCP_Server *tcp_s, Mono_Time *mono_time) { struct sec_TCP_con *sec_c = (struct sec_TCP_con *)malloc(sizeof(struct sec_TCP_con)); ck_assert(sec_c != nullptr); sec_c->ns = ns; sec_c->mem = mem; Socket sock = net_socket(ns, net_family_ipv6(), TOX_SOCK_STREAM, TOX_PROTO_TCP); IP_Port localhost; localhost.ip = get_loopback(); localhost.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); bool ok = net_connect(mem, logger, sock, &localhost); ck_assert_msg(ok, "Failed to connect to the test TCP relay server."); uint8_t f_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, sec_c->public_key, f_secret_key); random_nonce(rng, sec_c->sent_nonce); uint8_t t_secret_key[CRYPTO_SECRET_KEY_SIZE]; uint8_t handshake_plain[TCP_HANDSHAKE_PLAIN_SIZE]; crypto_new_keypair(rng, handshake_plain, t_secret_key); memcpy(handshake_plain + CRYPTO_PUBLIC_KEY_SIZE, sec_c->sent_nonce, CRYPTO_NONCE_SIZE); uint8_t handshake[TCP_CLIENT_HANDSHAKE_SIZE]; memcpy(handshake, sec_c->public_key, CRYPTO_PUBLIC_KEY_SIZE); random_nonce(rng, handshake + CRYPTO_PUBLIC_KEY_SIZE); int ret = encrypt_data(tcp_server_public_key(tcp_s), f_secret_key, handshake + CRYPTO_PUBLIC_KEY_SIZE, handshake_plain, TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), "Failed to encrypt the outgoing handshake."); ck_assert_msg(net_send(ns, logger, sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, &localhost) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "Failed to send the first portion of the handshake to the TCP relay server."); do_tcp_server_delay(tcp_s, mono_time, 50); ck_assert_msg(net_send(ns, logger, sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, &localhost) == 1, "Failed to send last byte of handshake."); do_tcp_server_delay(tcp_s, mono_time, 50); uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE]; ck_assert_msg(net_recv(sec_c->ns, logger, sock, response, TCP_SERVER_HANDSHAKE_SIZE, &localhost) == TCP_SERVER_HANDSHAKE_SIZE, "Failed to receive server handshake response."); ret = decrypt_data(tcp_server_public_key(tcp_s), f_secret_key, response, response + CRYPTO_NONCE_SIZE, TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain); ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Failed to decrypt server handshake response."); encrypt_precompute(response_plain, t_secret_key, sec_c->shared_key); memcpy(sec_c->recv_nonce, response_plain + CRYPTO_SHARED_KEY_SIZE, CRYPTO_NONCE_SIZE); sec_c->sock = sock; return sec_c; } static void kill_tcp_con(struct sec_TCP_con *con) { kill_sock(con->ns, con->sock); free(con); } static int write_packet_tcp_test_connection(const Logger *logger, struct sec_TCP_con *con, const uint8_t *data, uint16_t length) { const uint16_t packet_size = sizeof(uint16_t) + length + CRYPTO_MAC_SIZE; VLA(uint8_t, packet, packet_size); uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE); memcpy(packet, &c_length, sizeof(uint16_t)); int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (packet_size - sizeof(uint16_t))) { return -1; } increment_nonce(con->sent_nonce); IP_Port localhost; localhost.ip = get_loopback(); localhost.port = 0; ck_assert_msg(net_send(con->ns, logger, con->sock, packet, packet_size, &localhost) == packet_size, "Failed to send a packet."); return 0; } static int read_packet_sec_tcp(const Logger *logger, struct sec_TCP_con *con, uint8_t *data, uint16_t length) { IP_Port localhost; localhost.ip = get_loopback(); localhost.port = 0; int rlen = net_recv(con->ns, logger, con->sock, data, length, &localhost); ck_assert_msg(rlen == length, "Did not receive packet of correct length. Wanted %i, instead got %i", length, rlen); rlen = decrypt_data_symmetric(con->shared_key, con->recv_nonce, data + 2, length - 2, data); ck_assert_msg(rlen != -1, "Failed to decrypt a received packet from the Relay server."); increment_nonce(con->recv_nonce); return rlen; } static void test_some(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Logger *logger = logger_new(); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Server *tcp_s = new_tcp_server(logger, mem, rng, ns, USE_IPV6, NUM_PORTS, ports, self_secret_key, nullptr, nullptr); ck_assert_msg(tcp_s != nullptr, "Failed to create TCP relay server"); ck_assert_msg(tcp_server_listen_count(tcp_s) == NUM_PORTS, "Failed to bind to all ports."); struct sec_TCP_con *con1 = new_tcp_con(logger, mem, rng, ns, tcp_s, mono_time); struct sec_TCP_con *con2 = new_tcp_con(logger, mem, rng, ns, tcp_s, mono_time); struct sec_TCP_con *con3 = new_tcp_con(logger, mem, rng, ns, tcp_s, mono_time); uint8_t requ_p[1 + CRYPTO_PUBLIC_KEY_SIZE]; requ_p[0] = TCP_PACKET_ROUTING_REQUEST; // Sending wrong public keys to test server response. memcpy(requ_p + 1, con3->public_key, CRYPTO_PUBLIC_KEY_SIZE); write_packet_tcp_test_connection(logger, con1, requ_p, sizeof(requ_p)); memcpy(requ_p + 1, con1->public_key, CRYPTO_PUBLIC_KEY_SIZE); write_packet_tcp_test_connection(logger, con3, requ_p, sizeof(requ_p)); do_tcp_server_delay(tcp_s, mono_time, 50); // Testing response from connection 1 uint8_t data[2048]; int len = read_packet_sec_tcp(logger, con1, data, 2 + 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE); ck_assert_msg(len == 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE, "Wrong response packet length of %d.", len); ck_assert_msg(data[0] == TCP_PACKET_ROUTING_RESPONSE, "Wrong response packet id of %d.", data[0]); ck_assert_msg(data[1] == 16, "Server didn't refuse connection using wrong public key."); ck_assert_msg(pk_equal(data + 2, con3->public_key), "Key in response packet wrong."); // Connection 3 len = read_packet_sec_tcp(logger, con3, data, 2 + 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE); ck_assert_msg(len == 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE, "Wrong response packet length of %d.", len); ck_assert_msg(data[0] == TCP_PACKET_ROUTING_RESPONSE, "Wrong response packet id of %d.", data[0]); ck_assert_msg(data[1] == 16, "Server didn't refuse connection using wrong public key."); ck_assert_msg(pk_equal(data + 2, con1->public_key), "Key in response packet wrong."); uint8_t test_packet[512] = {16, 17, 16, 86, 99, 127, 255, 189, 78}; // What is this packet???? write_packet_tcp_test_connection(logger, con3, test_packet, sizeof(test_packet)); write_packet_tcp_test_connection(logger, con3, test_packet, sizeof(test_packet)); write_packet_tcp_test_connection(logger, con3, test_packet, sizeof(test_packet)); do_tcp_server_delay(tcp_s, mono_time, 50); len = read_packet_sec_tcp(logger, con1, data, 2 + 2 + CRYPTO_MAC_SIZE); ck_assert_msg(len == 2, "wrong len %d", len); ck_assert_msg(data[0] == TCP_PACKET_CONNECTION_NOTIFICATION, "wrong packet id %u", data[0]); ck_assert_msg(data[1] == 16, "wrong peer id %u", data[1]); len = read_packet_sec_tcp(logger, con3, data, 2 + 2 + CRYPTO_MAC_SIZE); ck_assert_msg(len == 2, "wrong len %d", len); ck_assert_msg(data[0] == TCP_PACKET_CONNECTION_NOTIFICATION, "wrong packet id %u", data[0]); ck_assert_msg(data[1] == 16, "wrong peer id %u", data[1]); len = read_packet_sec_tcp(logger, con1, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); len = read_packet_sec_tcp(logger, con1, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); len = read_packet_sec_tcp(logger, con1, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); write_packet_tcp_test_connection(logger, con1, test_packet, sizeof(test_packet)); write_packet_tcp_test_connection(logger, con1, test_packet, sizeof(test_packet)); write_packet_tcp_test_connection(logger, con1, test_packet, sizeof(test_packet)); do_tcp_server_delay(tcp_s, mono_time, 50); len = read_packet_sec_tcp(logger, con3, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); len = read_packet_sec_tcp(logger, con3, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); len = read_packet_sec_tcp(logger, con3, data, 2 + sizeof(test_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(test_packet), "wrong len %d", len); ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, "packet is wrong %u %u %u %u", data[0], data[1], data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]); uint8_t ping_packet[1 + sizeof(uint64_t)] = {TCP_PACKET_PING, 8, 6, 9, 67}; write_packet_tcp_test_connection(logger, con1, ping_packet, sizeof(ping_packet)); do_tcp_server_delay(tcp_s, mono_time, 50); len = read_packet_sec_tcp(logger, con1, data, 2 + sizeof(ping_packet) + CRYPTO_MAC_SIZE); ck_assert_msg(len == sizeof(ping_packet), "wrong len %d", len); ck_assert_msg(data[0] == TCP_PACKET_PONG, "wrong packet id %u", data[0]); ck_assert_msg(memcmp(ping_packet + 1, data + 1, sizeof(uint64_t)) == 0, "wrong packet data"); // Kill off the connections kill_tcp_server(tcp_s); kill_tcp_con(con1); kill_tcp_con(con2); kill_tcp_con(con3); logger_kill(logger); mono_time_free(mem, mono_time); } static int response_callback_good; static uint8_t response_callback_connection_id; static uint8_t response_callback_public_key[CRYPTO_PUBLIC_KEY_SIZE]; static int response_callback(void *object, uint8_t connection_id, const uint8_t *public_key) { if (set_tcp_connection_number((TCP_Client_Connection *)(void *)((char *)object - 2), connection_id, 7) != 0) { return 1; } response_callback_connection_id = connection_id; memcpy(response_callback_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); response_callback_good++; return 0; } static int status_callback_good; static uint8_t status_callback_connection_id; static uint8_t status_callback_status; static int status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status) { if (object != (void *)2) { return 1; } if (number != 7) { return 1; } status_callback_connection_id = connection_id; status_callback_status = status; status_callback_good++; return 0; } static int data_callback_good; static int data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length, void *userdata) { if (object != (void *)3) { return 1; } if (number != 7) { return 1; } if (length != 5) { return 1; } if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) { data_callback_good++; return 0; } return 1; } static int oob_data_callback_good; static uint8_t oob_pubkey[CRYPTO_PUBLIC_KEY_SIZE]; static int oob_data_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) { if (object != (void *)4) { return 1; } if (length != 5) { return 1; } if (!pk_equal(public_key, oob_pubkey)) { return 1; } if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) { oob_data_callback_good++; return 0; } return 1; } static void test_client(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Logger *logger = logger_new(); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Server *tcp_s = new_tcp_server(logger, mem, rng, ns, USE_IPV6, NUM_PORTS, ports, self_secret_key, nullptr, nullptr); ck_assert_msg(tcp_s != nullptr, "Failed to create a TCP relay server."); ck_assert_msg(tcp_server_listen_count(tcp_s) == NUM_PORTS, "Failed to bind the relay server to all ports."); uint8_t f_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t f_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, f_public_key, f_secret_key); IP_Port ip_port_tcp_s; ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); TCP_Client_Connection *conn = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, nullptr); // TCP sockets might need a moment before they can be written to. c_sleep(50); do_tcp_connection(logger, mono_time, conn, nullptr); // The connection status should be unconfirmed here because we have finished // sending our data and are awaiting a response. ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_UNCONFIRMED, "Wrong connection status. Expected: %d, is: %d.", TCP_CLIENT_UNCONFIRMED, tcp_con_status(conn)); do_tcp_server_delay(tcp_s, mono_time, 50); // Now let the server handle requests... const uint8_t loop_size = 3; for (uint8_t i = 0; i < loop_size; i++) { mono_time_update(mono_time); do_tcp_connection(logger, mono_time, conn, nullptr); // Run the connection loop. // The status of the connection should continue to be TCP_CLIENT_CONFIRMED after multiple subsequent do_tcp_connection() calls. ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_CONFIRMED, "Wrong connection status. Expected: %d, is: %d", TCP_CLIENT_CONFIRMED, tcp_con_status(conn)); c_sleep(i == loop_size - 1 ? 0 : 500); // Sleep for 500ms on all except third loop. } do_tcp_server_delay(tcp_s, mono_time, 50); // And still after the server runs again. ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_CONFIRMED, "Wrong status. Expected: %d, is: %d", TCP_CLIENT_CONFIRMED, tcp_con_status(conn)); uint8_t f2_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t f2_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, f2_public_key, f2_secret_key); ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); TCP_Client_Connection *conn2 = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key, nullptr); c_sleep(50); // The client should call this function (defined earlier) during the routing process. routing_response_handler(conn, response_callback, (char *)conn + 2); // The client should call this function when it receives a connection notification. routing_status_handler(conn, status_callback, (void *)2); // The client should call this function when routing_data_handler(conn, data_callback, (void *)3); // The client should call this function when sending out of band packets. oob_data_handler(conn, oob_data_callback, (void *)4); // These integers will increment per successful callback. oob_data_callback_good = response_callback_good = status_callback_good = data_callback_good = 0; do_tcp_connection(logger, mono_time, conn, nullptr); do_tcp_connection(logger, mono_time, conn2, nullptr); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connection(logger, mono_time, conn, nullptr); do_tcp_connection(logger, mono_time, conn2, nullptr); c_sleep(50); const uint8_t data[5] = {1, 2, 3, 4, 5}; memcpy(oob_pubkey, f2_public_key, CRYPTO_PUBLIC_KEY_SIZE); send_oob_packet(logger, conn2, f_public_key, data, 5); send_routing_request(logger, conn, f2_public_key); send_routing_request(logger, conn2, f_public_key); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connection(logger, mono_time, conn, nullptr); do_tcp_connection(logger, mono_time, conn2, nullptr); // All callback methods save data should have run during the above network prodding. ck_assert_msg(oob_data_callback_good == 1, "OOB callback not called"); ck_assert_msg(response_callback_good == 1, "Response callback not called."); ck_assert_msg(pk_equal(response_callback_public_key, f2_public_key), "Wrong public key."); ck_assert_msg(status_callback_good == 1, "Status callback not called."); ck_assert_msg(status_callback_status == 2, "Wrong status callback status."); ck_assert_msg(status_callback_connection_id == response_callback_connection_id, "Status and response callback connection IDs are not equal."); do_tcp_server_delay(tcp_s, mono_time, 50); ck_assert_msg(send_data(logger, conn2, 0, data, 5) == 1, "Failed a send_data() call."); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connection(logger, mono_time, conn, nullptr); do_tcp_connection(logger, mono_time, conn2, nullptr); ck_assert_msg(data_callback_good == 1, "Data callback was not called."); status_callback_good = 0; send_disconnect_request(logger, conn2, 0); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connection(logger, mono_time, conn, nullptr); do_tcp_connection(logger, mono_time, conn2, nullptr); ck_assert_msg(status_callback_good == 1, "Status callback not called"); ck_assert_msg(status_callback_status == 1, "Wrong status callback status."); // Kill off all connections and servers. kill_tcp_server(tcp_s); kill_tcp_connection(conn); kill_tcp_connection(conn2); logger_kill(logger); mono_time_free(mem, mono_time); } // Test how the client handles servers that don't respond. static void test_client_invalid(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Logger *logger = logger_new(); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); uint8_t f_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t f_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, f_public_key, f_secret_key); IP_Port ip_port_tcp_s; ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); TCP_Client_Connection *conn = new_tcp_connection(logger, mem, mono_time, rng, ns, &ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, nullptr); // Run the client's main loop but not the server. mono_time_update(mono_time); do_tcp_connection(logger, mono_time, conn, nullptr); c_sleep(50); // After 50ms of no response... ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_CONNECTING, "Wrong status. Expected: %d, is: %d.", TCP_CLIENT_CONNECTING, tcp_con_status(conn)); // After 5s... c_sleep(5000); mono_time_update(mono_time); do_tcp_connection(logger, mono_time, conn, nullptr); ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_CONNECTING, "Wrong status. Expected: %d, is: %d.", TCP_CLIENT_CONNECTING, tcp_con_status(conn)); // 11s... (Should wait for 10 before giving up.) c_sleep(6000); mono_time_update(mono_time); do_tcp_connection(logger, mono_time, conn, nullptr); ck_assert_msg(tcp_con_status(conn) == TCP_CLIENT_DISCONNECTED, "Wrong status. Expected: %d, is: %d.", TCP_CLIENT_DISCONNECTED, tcp_con_status(conn)); kill_tcp_connection(conn); logger_kill(logger); mono_time_free(mem, mono_time); } #include "../toxcore/TCP_connection.h" static bool tcp_data_callback_called; static int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t length, void *userdata) { if (object != (void *)120397) { return -1; } if (id != 123) { return -1; } if (length != 6) { return -1; } if (memcmp(data, "Gentoo", length) != 0) { return -1; } tcp_data_callback_called = 1; return 0; } static void test_tcp_connection(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Logger *logger = logger_new(); tcp_data_callback_called = 0; uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Server *tcp_s = new_tcp_server(logger, mem, rng, ns, USE_IPV6, NUM_PORTS, ports, self_secret_key, nullptr, nullptr); ck_assert_msg(pk_equal(tcp_server_public_key(tcp_s), self_public_key), "Wrong public key"); TCP_Proxy_Info proxy_info; proxy_info.proxy_type = TCP_PROXY_NONE; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Connections *tc_1 = new_tcp_connections(logger, mem, rng, ns, mono_time, self_secret_key, &proxy_info); ck_assert_msg(pk_equal(tcp_connections_public_key(tc_1), self_public_key), "Wrong public key"); crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Connections *tc_2 = new_tcp_connections(logger, mem, rng, ns, mono_time, self_secret_key, &proxy_info); ck_assert_msg(pk_equal(tcp_connections_public_key(tc_2), self_public_key), "Wrong public key"); IP_Port ip_port_tcp_s; ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); int connection = new_tcp_connection_to(tc_1, tcp_connections_public_key(tc_2), 123); ck_assert_msg(connection == 0, "Connection id wrong"); ck_assert_msg(add_tcp_relay_connection(tc_1, connection, &ip_port_tcp_s, tcp_server_public_key(tcp_s)) == 0, "Could not add tcp relay to connection\n"); ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); connection = new_tcp_connection_to(tc_2, tcp_connections_public_key(tc_1), 123); ck_assert_msg(connection == 0, "Connection id wrong"); ck_assert_msg(add_tcp_relay_connection(tc_2, connection, &ip_port_tcp_s, tcp_server_public_key(tcp_s)) == 0, "Could not add tcp relay to connection\n"); ck_assert_msg(new_tcp_connection_to(tc_2, tcp_connections_public_key(tc_1), 123) == -1, "Managed to read same connection\n"); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); int ret = send_packet_tcp_connection(tc_1, 0, (const uint8_t *)"Gentoo", 6); ck_assert_msg(ret == 0, "could not send packet."); set_packet_tcp_connection_callback(tc_2, &tcp_data_callback, (void *) 120397); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); ck_assert_msg(tcp_data_callback_called, "could not recv packet."); ck_assert_msg(tcp_connection_to_online_tcp_relays(tc_1, 0) == 1, "Wrong number of connected relays"); ck_assert_msg(kill_tcp_connection_to(tc_1, 0) == 0, "could not kill connection to\n"); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); ck_assert_msg(send_packet_tcp_connection(tc_1, 0, (const uint8_t *)"Gentoo", 6) == -1, "could send packet."); ck_assert_msg(kill_tcp_connection_to(tc_2, 0) == 0, "could not kill connection to\n"); kill_tcp_server(tcp_s); kill_tcp_connections(tc_1); kill_tcp_connections(tc_2); logger_kill(logger); mono_time_free(mem, mono_time); } static bool tcp_oobdata_callback_called; static int tcp_oobdata_callback(void *object, const uint8_t *public_key, unsigned int id, const uint8_t *data, uint16_t length, void *userdata) { const TCP_Connections *tcp_c = (const TCP_Connections *)object; if (length != 6) { return -1; } if (memcmp(data, "Gentoo", length) != 0) { return -1; } if (tcp_send_oob_packet(tcp_c, id, public_key, data, length) == 0) { tcp_oobdata_callback_called = 1; } return 0; } static void test_tcp_connection2(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); const Network *ns = os_network(); ck_assert(ns != nullptr); const Memory *mem = os_memory(); ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Logger *logger = logger_new(); tcp_oobdata_callback_called = 0; tcp_data_callback_called = 0; uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Server *tcp_s = new_tcp_server(logger, mem, rng, ns, USE_IPV6, NUM_PORTS, ports, self_secret_key, nullptr, nullptr); ck_assert_msg(pk_equal(tcp_server_public_key(tcp_s), self_public_key), "Wrong public key"); TCP_Proxy_Info proxy_info; proxy_info.proxy_type = TCP_PROXY_NONE; crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Connections *tc_1 = new_tcp_connections(logger, mem, rng, ns, mono_time, self_secret_key, &proxy_info); ck_assert_msg(pk_equal(tcp_connections_public_key(tc_1), self_public_key), "Wrong public key"); crypto_new_keypair(rng, self_public_key, self_secret_key); TCP_Connections *tc_2 = new_tcp_connections(logger, mem, rng, ns, mono_time, self_secret_key, &proxy_info); ck_assert_msg(pk_equal(tcp_connections_public_key(tc_2), self_public_key), "Wrong public key"); IP_Port ip_port_tcp_s; ip_port_tcp_s.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); ip_port_tcp_s.ip = get_loopback(); int connection = new_tcp_connection_to(tc_1, tcp_connections_public_key(tc_2), 123); ck_assert_msg(connection == 0, "Connection id wrong"); ck_assert_msg(add_tcp_relay_connection(tc_1, connection, &ip_port_tcp_s, tcp_server_public_key(tcp_s)) == 0, "Could not add tcp relay to connection\n"); ck_assert_msg(add_tcp_relay_global(tc_2, &ip_port_tcp_s, tcp_server_public_key(tcp_s)) == 0, "Could not add global relay"); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); int ret = send_packet_tcp_connection(tc_1, 0, (const uint8_t *)"Gentoo", 6); ck_assert_msg(ret == 0, "could not send packet."); set_oob_packet_tcp_connection_callback(tc_2, &tcp_oobdata_callback, tc_2); set_packet_tcp_connection_callback(tc_1, &tcp_data_callback, (void *) 120397); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); ck_assert_msg(tcp_oobdata_callback_called, "could not recv packet."); do_tcp_server_delay(tcp_s, mono_time, 50); do_tcp_connections(logger, tc_1, nullptr); do_tcp_connections(logger, tc_2, nullptr); ck_assert_msg(tcp_data_callback_called, "could not recv packet."); ck_assert_msg(kill_tcp_connection_to(tc_1, 0) == 0, "could not kill connection to\n"); kill_tcp_server(tcp_s); kill_tcp_connections(tc_1); kill_tcp_connections(tc_2); logger_kill(logger); mono_time_free(mem, mono_time); } static void tcp_suite(void) { test_basic(); test_some(); test_client(); test_client_invalid(); test_tcp_connection(); test_tcp_connection2(); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); tcp_suite(); return 0; } c-toxcore-0.2.20/auto_tests/toxav_basic_test.c0000644060175106017510000004076314714247532017410 0ustar robin#include #include #include #include #include #include "../testing/misc_tools.h" #include "../toxav/toxav.h" #include "../toxcore/crypto_core.h" #include "../toxcore/logger.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #define TEST_REGULAR_AV 1 #define TEST_REGULAR_A 1 #define TEST_REGULAR_V 1 #define TEST_REJECT 1 #define TEST_CANCEL 1 #define TEST_MUTE_UNMUTE 1 #define TEST_STOP_RESUME_PAYLOAD 1 #define TEST_PAUSE_RESUME_SEND 1 #define ck_assert_call_control(a, b, c) do { \ Toxav_Err_Call_Control cc_err; \ bool ok = toxav_call_control(a, b, c, &cc_err); \ if (!ok) { \ printf("toxav_call_control returned error %d\n", cc_err); \ } \ ck_assert(ok); \ ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK); \ } while (0) typedef struct { bool incoming; uint32_t state; } CallControl; static void clear_call_control(CallControl *cc) { const CallControl empty = {0}; *cc = empty; } /** * Callbacks */ static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) { printf("Handling CALL callback\n"); ((CallControl *)user_data)->incoming = true; } static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) { printf("Handling CALL STATE callback: %u\n", state); ((CallControl *)user_data)->state = state; } static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) { printf("Received video payload\n"); } static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, void *user_data) { printf("Received audio payload\n"); } static void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) { if (length == 7 && memcmp("gentoo", data, 7) == 0) { ck_assert(tox_friend_add_norequest(m, public_key, nullptr) != (uint32_t) -1); } } /** * Iterate helper */ static void iterate_tox(Tox *bootstrap, Tox *alice, Tox *bob) { c_sleep(100); tox_iterate(bootstrap, nullptr); tox_iterate(alice, nullptr); tox_iterate(bob, nullptr); } static bool toxav_audio_send_frame_helper(ToxAV *av, uint32_t friend_number, Toxav_Err_Send_Frame *error) { static const int16_t pcm[960] = {0}; return toxav_audio_send_frame(av, 0, pcm, 960, 1, 48000, nullptr); } static void regular_call_flow( Tox *alice, Tox *bob, Tox *bootstrap, ToxAV *alice_av, ToxAV *bob_av, CallControl *alice_cc, CallControl *bob_cc, int a_br, int v_br) { clear_call_control(alice_cc); clear_call_control(bob_cc); Toxav_Err_Call call_err; toxav_call(alice_av, 0, a_br, v_br, &call_err); ck_assert_msg(call_err == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", call_err); const time_t start_time = time(nullptr); do { if (bob_cc->incoming) { Toxav_Err_Answer answer_err; toxav_answer(bob_av, 0, a_br, v_br, &answer_err); ck_assert_msg(answer_err == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", answer_err); bob_cc->incoming = false; } else { /* TODO(mannol): rtp */ if (time(nullptr) - start_time >= 1) { Toxav_Err_Call_Control cc_err; toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err); ck_assert_msg(cc_err == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", cc_err); } } iterate_tox(bootstrap, alice, bob); } while (bob_cc->state != TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } static void test_av_flows(void) { Tox *alice, *bob, *bootstrap; ToxAV *alice_av, *bob_av; uint32_t index[] = { 1, 2, 3 }; CallControl alice_cc, bob_cc; { Tox_Err_New error; bootstrap = tox_new_log(nullptr, &error, &index[0]); ck_assert(error == TOX_ERR_NEW_OK); alice = tox_new_log(nullptr, &error, &index[1]); ck_assert(error == TOX_ERR_NEW_OK); bob = tox_new_log(nullptr, &error, &index[2]); ck_assert(error == TOX_ERR_NEW_OK); } printf("Created 3 instances of Tox\n"); printf("Preparing network...\n"); long long unsigned int cur_time = time(nullptr); uint8_t address[TOX_ADDRESS_SIZE]; tox_callback_friend_request(alice, t_accept_friend_request_cb); tox_self_get_address(alice, address); printf("bootstrapping Alice and Bob off a third bootstrap node\n"); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(bootstrap, dht_key); const uint16_t dht_port = tox_self_get_udp_port(bootstrap, nullptr); tox_bootstrap(alice, "localhost", dht_port, dht_key, nullptr); tox_bootstrap(bob, "localhost", dht_port, dht_key, nullptr); ck_assert(tox_friend_add(bob, address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); uint8_t off = 1; while (true) { iterate_tox(bootstrap, alice, bob); if (tox_self_get_connection_status(bootstrap) && tox_self_get_connection_status(alice) && tox_self_get_connection_status(bob) && off) { printf("Toxes are online, took %llu seconds\n", time(nullptr) - cur_time); off = 0; } if (tox_friend_get_connection_status(alice, 0, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(bob, 0, nullptr) == TOX_CONNECTION_UDP) { break; } c_sleep(20); } { Toxav_Err_New error; alice_av = toxav_new(alice, &error); ck_assert(error == TOXAV_ERR_NEW_OK); bob_av = toxav_new(bob, &error); ck_assert(error == TOXAV_ERR_NEW_OK); } toxav_callback_call(alice_av, t_toxav_call_cb, &alice_cc); toxav_callback_call_state(alice_av, t_toxav_call_state_cb, &alice_cc); toxav_callback_video_receive_frame(alice_av, t_toxav_receive_video_frame_cb, &alice_cc); toxav_callback_audio_receive_frame(alice_av, t_toxav_receive_audio_frame_cb, &alice_cc); toxav_callback_call(bob_av, t_toxav_call_cb, &bob_cc); toxav_callback_call_state(bob_av, t_toxav_call_state_cb, &bob_cc); toxav_callback_video_receive_frame(bob_av, t_toxav_receive_video_frame_cb, &bob_cc); toxav_callback_audio_receive_frame(bob_av, t_toxav_receive_audio_frame_cb, &bob_cc); printf("Created 2 instances of ToxAV\n"); printf("All set after %llu seconds!\n", time(nullptr) - cur_time); if (TEST_REGULAR_AV) { printf("\nTrying regular call (Audio and Video)...\n"); regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc, 48, 4000); } if (TEST_REGULAR_A) { printf("\nTrying regular call (Audio only)...\n"); regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc, 48, 0); } if (TEST_REGULAR_V) { printf("\nTrying regular call (Video only)...\n"); regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc, 0, 4000); } if (TEST_REJECT) { /* Alice calls; Bob rejects */ printf("\nTrying reject flow...\n"); clear_call_control(&alice_cc); clear_call_control(&bob_cc); { Toxav_Err_Call rc; toxav_call(alice_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (!bob_cc.incoming); /* Reject */ { Toxav_Err_Call_Control rc; toxav_call_control(bob_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (alice_cc.state != TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */ printf("\nTrying cancel (while ringing) flow...\n"); clear_call_control(&alice_cc); clear_call_control(&bob_cc); { Toxav_Err_Call rc; toxav_call(alice_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (!bob_cc.incoming); /* Cancel */ { Toxav_Err_Call_Control rc; toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc); } /* Alice will not receive end state */ do { iterate_tox(bootstrap, alice, bob); } while (bob_cc.state != TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */ printf("\nTrying mute functionality...\n"); clear_call_control(&alice_cc); clear_call_control(&bob_cc); /* Assume sending audio and video */ { Toxav_Err_Call rc; toxav_call(alice_av, 0, 48, 1000, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (!bob_cc.incoming); /* At first try all stuff while in invalid state */ ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE, nullptr)); ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME, nullptr)); ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, nullptr)); ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, nullptr)); ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO, nullptr)); ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO, nullptr)); { Toxav_Err_Answer rc; toxav_answer(bob_av, 0, 48, 4000, &rc); ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); /* Pause and Resume */ printf("Pause and Resume\n"); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state == 0); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state & (TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_SENDING_V)); /* Mute/Unmute single */ printf("Mute/Unmute single\n"); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A); /* Mute/Unmute both */ printf("Mute/Unmute both\n"); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_V); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V); { Toxav_Err_Call_Control rc; toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } if (TEST_STOP_RESUME_PAYLOAD) { /* Stop and resume audio/video payload */ printf("\nTrying stop/resume functionality...\n"); clear_call_control(&alice_cc); clear_call_control(&bob_cc); /* Assume sending audio and video */ { Toxav_Err_Call rc; toxav_call(alice_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (!bob_cc.incoming); { Toxav_Err_Answer rc; toxav_answer(bob_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); printf("Call started as audio only\n"); printf("Turning on video for Alice...\n"); ck_assert(toxav_video_set_bit_rate(alice_av, 0, 1000, nullptr)); iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_V); printf("Turning off video for Alice...\n"); ck_assert(toxav_video_set_bit_rate(alice_av, 0, 0, nullptr)); iterate_tox(bootstrap, alice, bob); ck_assert(!(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_V)); printf("Turning off audio for Alice...\n"); ck_assert(toxav_audio_set_bit_rate(alice_av, 0, 0, nullptr)); iterate_tox(bootstrap, alice, bob); ck_assert(!(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_A)); { Toxav_Err_Call_Control rc; toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } if (TEST_PAUSE_RESUME_SEND) { /* Stop and resume audio/video payload and test send options */ printf("\nTrying stop/resume functionality...\n"); clear_call_control(&alice_cc); clear_call_control(&bob_cc); /* Assume sending audio and video */ { Toxav_Err_Call rc; toxav_call(alice_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc); } do { iterate_tox(bootstrap, alice, bob); } while (!bob_cc.incoming); { Toxav_Err_Answer rc; toxav_answer(bob_av, 0, 48, 0, &rc); ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE); iterate_tox(bootstrap, alice, bob); ck_assert(!toxav_audio_send_frame_helper(alice_av, 0, nullptr)); ck_assert(!toxav_audio_send_frame_helper(bob_av, 0, nullptr)); ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME); iterate_tox(bootstrap, alice, bob); ck_assert(toxav_audio_send_frame_helper(alice_av, 0, nullptr)); ck_assert(toxav_audio_send_frame_helper(bob_av, 0, nullptr)); iterate_tox(bootstrap, alice, bob); { Toxav_Err_Call_Control rc; toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc); } iterate_tox(bootstrap, alice, bob); ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED); printf("Success!\n"); } toxav_kill(bob_av); toxav_kill(alice_av); tox_kill(bob); tox_kill(alice); tox_kill(bootstrap); printf("\nTest successful!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_av_flows(); return 0; } c-toxcore-0.2.20/auto_tests/toxav_many_test.c0000644060175106017510000002724614714247532017274 0ustar robin#include #include #include #include #include #include #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) #include #endif #include #include "../testing/misc_tools.h" #include "../toxav/toxav.h" #include "../toxcore/crypto_core.h" #include "../toxcore/logger.h" #include "../toxcore/tox.h" #include "../toxcore/tox_struct.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" typedef struct CallControl { bool incoming; uint32_t state; } CallControl; typedef struct Thread_Data { ToxAV *alice_av; ToxAV *bob_av; CallControl *alice_cc; CallControl *bob_cc; uint32_t friend_number; } Thread_Data; /** * Callbacks */ static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) { printf("Handling CALL callback\n"); ((CallControl *)user_data)[friend_number].incoming = true; } static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) { printf("Handling CALL STATE callback: %u %p\n", state, (void *)av); ((CallControl *)user_data)[friend_number].state = state; } static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) { } static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, void *user_data) { } static void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) { if (length == 7 && memcmp("gentoo", data, 7) == 0) { ck_assert(tox_friend_add_norequest(m, public_key, nullptr) != (uint32_t) -1); } } /** * Iterate helper */ static ToxAV *setup_av_instance(Tox *tox, CallControl *cc) { Toxav_Err_New error; ToxAV *av = toxav_new(tox, &error); ck_assert(error == TOXAV_ERR_NEW_OK); toxav_callback_call(av, t_toxav_call_cb, cc); toxav_callback_call_state(av, t_toxav_call_state_cb, cc); toxav_callback_video_receive_frame(av, t_toxav_receive_video_frame_cb, cc); toxav_callback_audio_receive_frame(av, t_toxav_receive_audio_frame_cb, cc); return av; } static void *call_thread(void *pd) { ToxAV *alice_av = ((Thread_Data *) pd)->alice_av; ToxAV *bob_av = ((Thread_Data *) pd)->bob_av; uint32_t friend_number = ((Thread_Data *) pd)->friend_number; int16_t *pcm = (int16_t *)calloc(960, sizeof(int16_t)); uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); time_t start_time = time(nullptr); do { toxav_iterate(alice_av); toxav_iterate(bob_av); toxav_audio_send_frame(alice_av, friend_number, pcm, 960, 1, 48000, nullptr); toxav_audio_send_frame(bob_av, 0, pcm, 960, 1, 48000, nullptr); toxav_video_send_frame(alice_av, friend_number, 800, 600, video_y, video_u, video_v, nullptr); toxav_video_send_frame(bob_av, 0, 800, 600, video_y, video_u, video_v, nullptr); c_sleep(10); } while (time(nullptr) - start_time < 4); free(pcm); free(video_y); free(video_u); free(video_v); printf("Closing thread\n"); pthread_exit(nullptr); return nullptr; } typedef struct Time_Data { pthread_mutex_t lock; uint64_t clock; } Time_Data; static uint64_t get_state_clock_callback(void *user_data) { Time_Data *time_data = (Time_Data *)user_data; pthread_mutex_lock(&time_data->lock); uint64_t clock = time_data->clock; pthread_mutex_unlock(&time_data->lock); return clock; } static void increment_clock(Time_Data *time_data, uint64_t count) { pthread_mutex_lock(&time_data->lock); time_data->clock += count; pthread_mutex_unlock(&time_data->lock); } static void set_current_time_callback(Tox *tox, Time_Data *time_data) { Mono_Time *mono_time = tox->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data); } static void test_av_three_calls(void) { uint32_t index[] = { 1, 2, 3, 4, 5 }; Tox *alice, *bootstrap, *bobs[3]; ToxAV *alice_av, *bobs_av[3]; void *retval; CallControl alice_cc[3], bobs_cc[3]; Time_Data time_data; pthread_mutex_init(&time_data.lock, nullptr); { Tox_Options *opts = tox_options_new(nullptr); ck_assert(opts != nullptr); tox_options_set_experimental_thread_safety(opts, true); Tox_Err_New error; bootstrap = tox_new_log(opts, &error, &index[0]); ck_assert(error == TOX_ERR_NEW_OK); time_data.clock = current_time_monotonic(bootstrap->mono_time); set_current_time_callback(bootstrap, &time_data); alice = tox_new_log(opts, &error, &index[1]); ck_assert(error == TOX_ERR_NEW_OK); set_current_time_callback(alice, &time_data); bobs[0] = tox_new_log(opts, &error, &index[2]); ck_assert(error == TOX_ERR_NEW_OK); set_current_time_callback(bobs[0], &time_data); bobs[1] = tox_new_log(opts, &error, &index[3]); ck_assert(error == TOX_ERR_NEW_OK); set_current_time_callback(bobs[1], &time_data); bobs[2] = tox_new_log(opts, &error, &index[4]); ck_assert(error == TOX_ERR_NEW_OK); set_current_time_callback(bobs[2], &time_data); tox_options_free(opts); } printf("Created 5 instances of Tox\n"); printf("Preparing network...\n"); time_t cur_time = time(nullptr); uint8_t address[TOX_ADDRESS_SIZE]; tox_callback_friend_request(alice, t_accept_friend_request_cb); tox_self_get_address(alice, address); printf("bootstrapping Alice and the %u Bobs off a third bootstrap node\n", (unsigned)(sizeof(bobs) / sizeof(bobs[0]))); uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(bootstrap, dht_key); const uint16_t dht_port = tox_self_get_udp_port(bootstrap, nullptr); tox_bootstrap(alice, "localhost", dht_port, dht_key, nullptr); tox_bootstrap(bobs[0], "localhost", dht_port, dht_key, nullptr); tox_bootstrap(bobs[1], "localhost", dht_port, dht_key, nullptr); tox_bootstrap(bobs[2], "localhost", dht_port, dht_key, nullptr); ck_assert(tox_friend_add(bobs[0], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); ck_assert(tox_friend_add(bobs[1], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); ck_assert(tox_friend_add(bobs[2], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); uint8_t off = 1; while (true) { tox_iterate(bootstrap, nullptr); tox_iterate(alice, nullptr); tox_iterate(bobs[0], nullptr); tox_iterate(bobs[1], nullptr); tox_iterate(bobs[2], nullptr); if (tox_self_get_connection_status(bootstrap) && tox_self_get_connection_status(alice) && tox_self_get_connection_status(bobs[0]) && tox_self_get_connection_status(bobs[1]) && tox_self_get_connection_status(bobs[2]) && off) { printf("Toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); off = 0; } if (tox_friend_get_connection_status(alice, 0, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(alice, 1, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(alice, 2, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(bobs[0], 0, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(bobs[1], 0, nullptr) == TOX_CONNECTION_UDP && tox_friend_get_connection_status(bobs[2], 0, nullptr) == TOX_CONNECTION_UDP) { break; } increment_clock(&time_data, 200); c_sleep(5); } alice_av = setup_av_instance(alice, alice_cc); bobs_av[0] = setup_av_instance(bobs[0], &bobs_cc[0]); bobs_av[1] = setup_av_instance(bobs[1], &bobs_cc[1]); bobs_av[2] = setup_av_instance(bobs[2], &bobs_cc[2]); printf("Created 4 instances of ToxAV\n"); printf("All set after %lu seconds!\n", (unsigned long)(time(nullptr) - cur_time)); Thread_Data tds[3]; for (size_t i = 0; i < 3; i++) { tds[i].alice_av = alice_av; tds[i].bob_av = bobs_av[i]; tds[i].alice_cc = &alice_cc[i]; tds[i].bob_cc = &bobs_cc[i]; tds[i].friend_number = i; memset(tds[i].alice_cc, 0, sizeof(CallControl)); memset(tds[i].bob_cc, 0, sizeof(CallControl)); } pthread_t tids[3]; for (size_t i = 0; i < 3; i++) { (void) pthread_create(&tids[i], nullptr, call_thread, &tds[i]); } time_t start_time = time(nullptr); do { tox_iterate(bootstrap, nullptr); tox_iterate(alice, nullptr); tox_iterate(bobs[0], nullptr); tox_iterate(bobs[1], nullptr); tox_iterate(bobs[2], nullptr); increment_clock(&time_data, 100); c_sleep(5); } while (time(nullptr) - start_time < 1); /* Call */ for (size_t i = 0; i < 3; i++) { Toxav_Err_Call rc; toxav_call(alice_av, tds[i].friend_number, 48, 3000, &rc); if (rc != TOXAV_ERR_CALL_OK) { printf("toxav_call failed: %d\n", rc); ck_assert(0); } } do { tox_iterate(bootstrap, nullptr); tox_iterate(alice, nullptr); tox_iterate(bobs[0], nullptr); tox_iterate(bobs[1], nullptr); tox_iterate(bobs[2], nullptr); for (size_t i = 0; i < 3; i++) { if (bobs_cc[i].incoming) { /* Answer */ Toxav_Err_Answer rc; toxav_answer(bobs_av[i], 0, 8, 500, &rc); if (rc != TOXAV_ERR_ANSWER_OK) { printf("toxav_answer failed: %d\n", rc); ck_assert(0); } bobs_cc[i].incoming = false; } } increment_clock(&time_data, 100); c_sleep(5); } while (time(nullptr) - start_time < 3); /* Hangup */ for (size_t i = 0; i < 3; i++) { Toxav_Err_Call_Control rc; toxav_call_control(alice_av, i, TOXAV_CALL_CONTROL_CANCEL, &rc); if (rc != TOXAV_ERR_CALL_CONTROL_OK) { printf("toxav_call_control failed: %d %p %p\n", rc, (void *)alice_av, (void *)&bobs_av[i]); } } do { tox_iterate(bootstrap, nullptr); tox_iterate(alice, nullptr); tox_iterate(bobs[0], nullptr); tox_iterate(bobs[1], nullptr); tox_iterate(bobs[2], nullptr); increment_clock(&time_data, 100); c_sleep(5); } while (time(nullptr) - start_time < 5); ck_assert(pthread_join(tids[0], &retval) == 0); ck_assert(retval == nullptr); ck_assert(pthread_join(tids[1], &retval) == 0); ck_assert(retval == nullptr); ck_assert(pthread_join(tids[2], &retval) == 0); ck_assert(retval == nullptr); printf("Killing all instances\n"); toxav_kill(bobs_av[2]); toxav_kill(bobs_av[1]); toxav_kill(bobs_av[0]); toxav_kill(alice_av); tox_kill(bobs[2]); tox_kill(bobs[1]); tox_kill(bobs[0]); tox_kill(alice); tox_kill(bootstrap); pthread_mutex_destroy(&time_data.lock); printf("\nTest successful!\n"); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_av_three_calls(); return 0; } c-toxcore-0.2.20/auto_tests/tox_dispatch_test.c0000644060175106017510000001267014714247532017573 0ustar robin/* Auto Tests: Many clients. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/tox.h" #include "../toxcore/tox_dispatch.h" #include "../toxcore/tox_events.h" #include "../toxcore/tox_private.h" #include "../toxcore/tox_unpack.h" #include "auto_test_support.h" #include "check_compat.h" // Set to true to produce an msgpack file at /tmp/test.mp. static const bool want_dump_events = false; static void handle_events_friend_message(const Tox_Event_Friend_Message *event, void *user_data) { bool *success = (bool *)user_data; ck_assert(tox_event_friend_message_get_message_length(event) == sizeof("hello")); const uint8_t *msg = tox_event_friend_message_get_message(event); ck_assert_msg(memcmp(msg, "hello", sizeof("hello")) == 0, "message was not expected 'hello' but '%s'", (const char *)msg); *success = true; } static void dump_events(const char *path, const Tox_Events *events) { FILE *fh = fopen(path, "w"); ck_assert(fh != nullptr); const uint32_t len = tox_events_bytes_size(events); uint8_t *buf = (uint8_t *)malloc(len); ck_assert(buf != nullptr); ck_assert(tox_events_get_bytes(events, buf)); fwrite(buf, 1, len, fh); free(buf); fclose(fh); } static void print_events(const Tox_System *sys, Tox_Events *events) { const uint32_t size = tox_events_bytes_size(events); uint8_t *bytes1 = (uint8_t *)malloc(size); uint8_t *bytes2 = (uint8_t *)malloc(size); ck_assert(bytes1 != nullptr); ck_assert(bytes2 != nullptr); ck_assert(tox_events_get_bytes(events, bytes1)); ck_assert(tox_events_get_bytes(events, bytes2)); // Make sure get_bytes is deterministic. ck_assert(memcmp(bytes1, bytes2, size) == 0); Tox_Events *events_copy = tox_events_load(sys, bytes1, size); ck_assert(events_copy != nullptr); free(bytes1); free(bytes2); ck_assert(tox_events_equal(sys, events, events_copy)); tox_events_free(events_copy); tox_events_free(events); } static bool await_message(Tox **toxes, const Tox_Dispatch *dispatch) { const Tox_System *sys = tox_get_system(toxes[0]); for (uint32_t i = 0; i < 100; ++i) { // Ignore events on tox 1. print_events(sys, tox_events_iterate(toxes[0], false, nullptr)); // Check if tox 2 got the message from tox 1. Tox_Events *events = tox_events_iterate(toxes[1], false, nullptr); if (want_dump_events) { dump_events("/tmp/test.mp", events); } bool success = false; tox_dispatch_invoke(dispatch, events, &success); print_events(sys, events); if (success) { return true; } c_sleep(tox_iteration_interval(toxes[0])); } return false; } static void test_tox_events(void) { uint8_t message[sizeof("hello")]; memcpy(message, "hello", sizeof(message)); Tox *toxes[2]; uint32_t index[2]; for (uint32_t i = 0; i < 2; ++i) { index[i] = i + 1; toxes[i] = tox_new_log(nullptr, nullptr, &index[i]); tox_events_init(toxes[i]); ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i); } const Tox_System *sys = tox_get_system(toxes[0]); Tox_Err_Dispatch_New err_new; Tox_Dispatch *dispatch = tox_dispatch_new(&err_new); ck_assert_msg(dispatch != nullptr, "failed to create event dispatcher"); ck_assert(err_new == TOX_ERR_DISPATCH_NEW_OK); tox_events_callback_friend_message(dispatch, handle_events_friend_message); uint8_t pk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(toxes[0], pk); tox_bootstrap(toxes[1], "localhost", tox_self_get_udp_port(toxes[0], nullptr), pk, nullptr); tox_self_get_public_key(toxes[0], pk); tox_friend_add_norequest(toxes[1], pk, nullptr); tox_self_get_public_key(toxes[1], pk); tox_friend_add_norequest(toxes[0], pk, nullptr); printf("bootstrapping and connecting 2 toxes\n"); while (tox_self_get_connection_status(toxes[0]) == TOX_CONNECTION_NONE || tox_self_get_connection_status(toxes[1]) == TOX_CONNECTION_NONE) { // Ignore connection events for now. print_events(sys, tox_events_iterate(toxes[0], false, nullptr)); print_events(sys, tox_events_iterate(toxes[1], false, nullptr)); c_sleep(tox_iteration_interval(toxes[0])); } printf("toxes online, waiting for friend connection\n"); while (tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(toxes[1], 0, nullptr) == TOX_CONNECTION_NONE) { // Ignore connection events for now. print_events(sys, tox_events_iterate(toxes[0], false, nullptr)); print_events(sys, tox_events_iterate(toxes[1], false, nullptr)); c_sleep(tox_iteration_interval(toxes[0])); } printf("friends are connected via %s, now sending message\n", tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_TCP ? "TCP" : "UDP"); Tox_Err_Friend_Send_Message err; tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof(message), &err); ck_assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK); ck_assert(await_message(toxes, dispatch)); tox_dispatch_free(dispatch); for (uint32_t i = 0; i < 2; ++i) { tox_kill(toxes[i]); } } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_tox_events(); return 0; } c-toxcore-0.2.20/auto_tests/tox_events_test.c0000644060175106017510000001051714714247532017276 0ustar robin/* Auto Tests: Many clients. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/tox.h" #include "../toxcore/tox_events.h" #include "../toxcore/tox_struct.h" #include "auto_test_support.h" #include "check_compat.h" static bool await_message(Tox **toxes) { for (uint32_t i = 0; i < 100; ++i) { // Ignore events on tox 1. tox_events_free(tox_events_iterate(toxes[0], false, nullptr)); // Check if tox 2 got the message from tox 1. Tox_Events *events = tox_events_iterate(toxes[1], false, nullptr); if (events != nullptr) { uint32_t events_size = tox_events_get_size(events); ck_assert(events_size == 1); const Tox_Event_Friend_Message *msg_event = nullptr; for (uint32_t j = 0; j < events_size; ++j) { const Tox_Event *ev = tox_events_get(events, j); if (tox_event_get_type(ev) == TOX_EVENT_FRIEND_MESSAGE) { msg_event = tox_event_get_friend_message(ev); } } ck_assert(msg_event != nullptr); ck_assert(tox_event_friend_message_get_message_length(msg_event) == sizeof("hello")); const uint8_t *msg = tox_event_friend_message_get_message(msg_event); ck_assert_msg(memcmp(msg, "hello", sizeof("hello")) == 0, "message was not expected 'hello' but '%s'", (const char *)msg); tox_events_free(events); return true; } c_sleep(tox_iteration_interval(toxes[0])); } return false; } static uint64_t get_state_clock_callback(void *user_data) { const uint64_t *clock = (const uint64_t *)user_data; return *clock; } static void test_tox_events(void) { uint8_t message[sizeof("hello")]; memcpy(message, "hello", sizeof(message)); Tox *toxes[2]; uint32_t index[2]; for (uint32_t i = 0; i < 2; ++i) { index[i] = i + 1; toxes[i] = tox_new_log(nullptr, nullptr, &index[i]); tox_events_init(toxes[i]); ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i); } uint64_t clock = current_time_monotonic(toxes[0]->mono_time); Mono_Time *mono_time; mono_time = toxes[0]->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock); mono_time = toxes[1]->mono_time; mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock); uint8_t pk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(toxes[0], pk); tox_bootstrap(toxes[1], "localhost", tox_self_get_udp_port(toxes[0], nullptr), pk, nullptr); tox_self_get_public_key(toxes[0], pk); tox_friend_add_norequest(toxes[1], pk, nullptr); tox_self_get_public_key(toxes[1], pk); tox_friend_add_norequest(toxes[0], pk, nullptr); printf("bootstrapping and connecting 2 toxes\n"); while (tox_self_get_connection_status(toxes[0]) == TOX_CONNECTION_NONE || tox_self_get_connection_status(toxes[1]) == TOX_CONNECTION_NONE) { // Ignore connection events for now. tox_events_free(tox_events_iterate(toxes[0], false, nullptr)); tox_events_free(tox_events_iterate(toxes[1], false, nullptr)); clock += 100; c_sleep(5); } printf("toxes online, waiting for friend connection\n"); while (tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_NONE || tox_friend_get_connection_status(toxes[1], 0, nullptr) == TOX_CONNECTION_NONE) { // Ignore connection events for now. tox_events_free(tox_events_iterate(toxes[0], false, nullptr)); tox_events_free(tox_events_iterate(toxes[1], false, nullptr)); clock += 100; c_sleep(5); } printf("friends are connected via %s, now sending message\n", tox_friend_get_connection_status(toxes[0], 0, nullptr) == TOX_CONNECTION_TCP ? "TCP" : "UDP"); Tox_Err_Friend_Send_Message err; tox_friend_send_message(toxes[0], 0, TOX_MESSAGE_TYPE_NORMAL, message, sizeof(message), &err); ck_assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK); ck_assert(await_message(toxes)); for (uint32_t i = 0; i < 2; ++i) { tox_kill(toxes[i]); } } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_tox_events(); return 0; } c-toxcore-0.2.20/auto_tests/tox_many_tcp_test.c0000644060175106017510000002154514714247532017607 0ustar robin/* Auto Tests: Many TCP. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/crypto_core.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" #ifndef USE_IPV6 #define USE_IPV6 1 #endif #ifdef TOX_LOCALHOST #undef TOX_LOCALHOST #endif #if USE_IPV6 #define TOX_LOCALHOST "::1" #else #define TOX_LOCALHOST "127.0.0.1" #endif typedef struct State { uint32_t to_comp; Tox *tox; } State; static bool enable_broken_tests = false; static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { State *state = (State *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *message = tox_event_friend_request_get_message(event); const uint32_t message_length = tox_event_friend_request_get_message_length(event); if (state->to_comp != 974536) { return; } if (message_length == 7 && memcmp("Gentoo", message, 7) == 0) { tox_friend_add_norequest(state->tox, public_key, nullptr); } } #define NUM_FRIENDS 50 #define NUM_TOXES_TCP 40 static uint16_t tcp_relay_port = 33448; static void test_many_clients_tcp(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); long long unsigned int cur_time = time(nullptr); Tox *toxes[NUM_TOXES_TCP]; uint32_t index[NUM_TOXES_TCP]; uint32_t to_comp = 974536; for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { struct Tox_Options *opts = tox_options_new(nullptr); if (i == 0) { tox_options_set_tcp_port(opts, tcp_relay_port); } else { tox_options_set_udp_enabled(opts, false); } index[i] = i + 1; Tox_Err_New err; toxes[i] = tox_new_log(opts, &err, &index[i]); if (i == 0 && err == TOX_ERR_NEW_PORT_ALLOC) { ck_assert(toxes[i] == nullptr); --i; ++tcp_relay_port; tox_options_free(opts); continue; } ck_assert_msg(toxes[i] != nullptr, "Failed to create tox instances %u", i); tox_events_init(toxes[i]); uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(toxes[0], dpk); Tox_Err_Bootstrap error; ck_assert_msg(tox_add_tcp_relay(toxes[i], TOX_LOCALHOST, tcp_relay_port, dpk, &error), "add relay error, %u, %d", i, error); uint16_t first_port = tox_self_get_udp_port(toxes[0], nullptr); ck_assert_msg(tox_bootstrap(toxes[i], TOX_LOCALHOST, first_port, dpk, nullptr), "Bootstrap error"); tox_options_free(opts); } Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); tox_events_callback_friend_request(dispatch, accept_friend_request); struct { uint16_t tox1; uint16_t tox2; } pairs[NUM_FRIENDS]; uint8_t address[TOX_ADDRESS_SIZE]; for (uint32_t i = 0; i < NUM_FRIENDS; ++i) { loop_top: pairs[i].tox1 = random_u32(rng) % NUM_TOXES_TCP; pairs[i].tox2 = (pairs[i].tox1 + random_u32(rng) % (NUM_TOXES_TCP - 1) + 1) % NUM_TOXES_TCP; for (uint32_t j = 0; j < i; ++j) { if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2) { goto loop_top; } } tox_self_get_address(toxes[pairs[i].tox1], address); Tox_Err_Friend_Add test; uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (const uint8_t *)"Gentoo", 7, &test); if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) { goto loop_top; } ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, "Failed to add friend error code: %i", test); } while (true) { uint16_t counter = 0; for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { for (uint32_t j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j) { if (tox_friend_get_connection_status(toxes[i], j, nullptr) == TOX_CONNECTION_TCP) { ++counter; } } } if (counter == NUM_FRIENDS * 2) { break; } for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(toxes[i], true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); State state = {to_comp, toxes[i]}; tox_dispatch_invoke(dispatch, events, &state); tox_events_free(events); } c_sleep(50); } tox_dispatch_free(dispatch); for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { tox_kill(toxes[i]); } printf("test_many_clients_tcp succeeded, took %llu seconds\n", time(nullptr) - cur_time); } #define NUM_TCP_RELAYS 3 static void test_many_clients_tcp_b(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); long long unsigned int cur_time = time(nullptr); Tox *toxes[NUM_TOXES_TCP]; uint32_t index[NUM_TOXES_TCP]; uint32_t to_comp = 974536; for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { struct Tox_Options *opts = tox_options_new(nullptr); if (i < NUM_TCP_RELAYS) { tox_options_set_tcp_port(opts, tcp_relay_port + i); } else { tox_options_set_udp_enabled(opts, 0); } index[i] = i + 1; toxes[i] = tox_new_log(opts, nullptr, &index[i]); ck_assert_msg(toxes[i] != nullptr, "Failed to create tox instances %u", i); tox_events_init(toxes[i]); uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(toxes[(i % NUM_TCP_RELAYS)], dpk); ck_assert_msg(tox_add_tcp_relay(toxes[i], TOX_LOCALHOST, tcp_relay_port + (i % NUM_TCP_RELAYS), dpk, nullptr), "add relay error"); tox_self_get_dht_id(toxes[0], dpk); uint16_t first_port = tox_self_get_udp_port(toxes[0], nullptr); ck_assert_msg(tox_bootstrap(toxes[i], TOX_LOCALHOST, first_port, dpk, nullptr), "Bootstrap error"); tox_options_free(opts); } Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); tox_events_callback_friend_request(dispatch, accept_friend_request); struct { uint16_t tox1; uint16_t tox2; } pairs[NUM_FRIENDS]; uint8_t address[TOX_ADDRESS_SIZE]; for (uint32_t i = 0; i < NUM_FRIENDS; ++i) { loop_top: pairs[i].tox1 = random_u32(rng) % NUM_TOXES_TCP; pairs[i].tox2 = (pairs[i].tox1 + random_u32(rng) % (NUM_TOXES_TCP - 1) + 1) % NUM_TOXES_TCP; for (uint32_t j = 0; j < i; ++j) { if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2) { goto loop_top; } } tox_self_get_address(toxes[pairs[i].tox1], address); Tox_Err_Friend_Add test; uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (const uint8_t *)"Gentoo", 7, &test); if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) { goto loop_top; } ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, "Failed to add friend error code: %i", test); } uint16_t last_count = 0; while (true) { uint16_t counter = 0; for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { for (uint32_t j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j) { if (tox_friend_get_connection_status(toxes[i], j, nullptr) == TOX_CONNECTION_TCP) { ++counter; } } } if (counter != last_count) { printf("many_clients_tcp_b got to %u\n", counter); last_count = counter; } if (counter == NUM_FRIENDS * 2) { break; } for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(toxes[i], true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); State state = {to_comp, toxes[i]}; tox_dispatch_invoke(dispatch, events, &state); tox_events_free(events); } c_sleep(30); } tox_dispatch_free(dispatch); for (uint32_t i = 0; i < NUM_TOXES_TCP; ++i) { tox_kill(toxes[i]); } printf("test_many_clients_tcp_b succeeded, took %llu seconds\n", time(nullptr) - cur_time); } static void tox_suite(void) { /* Each tox connects to a single tox TCP */ test_many_clients_tcp(); if (enable_broken_tests) { /* Try to make a connection to each "older sibling" tox instance via TCP */ /* Currently this test intermittently fails for unknown reasons. */ test_many_clients_tcp_b(); } } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); tox_suite(); return 0; } c-toxcore-0.2.20/auto_tests/tox_many_test.c0000644060175106017510000001070114714247532016731 0ustar robin/* Auto Tests: Many clients. */ #include #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/crypto_core.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "auto_test_support.h" #include "check_compat.h" static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { Tox *tox = (Tox *)userdata; const uint8_t *public_key = tox_event_friend_request_get_public_key(event); const uint8_t *message = tox_event_friend_request_get_message(event); const uint32_t message_length = tox_event_friend_request_get_message_length(event); if (message_length == 7 && memcmp("Gentoo", message, 7) == 0) { tox_friend_add_norequest(tox, public_key, nullptr); } } #define TCP_TEST_NUM_TOXES 90 #define TCP_TEST_NUM_FRIENDS 50 static void test_many_clients(void) { const Random *rng = os_random(); ck_assert(rng != nullptr); time_t cur_time = time(nullptr); Tox *toxes[TCP_TEST_NUM_TOXES]; uint32_t index[TCP_TEST_NUM_TOXES]; for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { index[i] = i + 1; toxes[i] = tox_new_log(nullptr, nullptr, &index[i]); ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i); tox_events_init(toxes[i]); } Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); tox_events_callback_friend_request(dispatch, accept_friend_request); struct { uint16_t tox1; uint16_t tox2; } pairs[TCP_TEST_NUM_FRIENDS]; uint8_t address[TOX_ADDRESS_SIZE]; uint32_t num_f = 0; for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { num_f += tox_self_get_friend_list_size(toxes[i]); } ck_assert_msg(num_f == 0, "bad num friends: %u", num_f); for (uint32_t i = 0; i < TCP_TEST_NUM_FRIENDS; ++i) { loop_top: pairs[i].tox1 = random_u32(rng) % TCP_TEST_NUM_TOXES; pairs[i].tox2 = (pairs[i].tox1 + random_u32(rng) % (TCP_TEST_NUM_TOXES - 1) + 1) % TCP_TEST_NUM_TOXES; for (uint32_t j = 0; j < i; ++j) { if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2) { goto loop_top; } } tox_self_get_address(toxes[pairs[i].tox1], address); Tox_Err_Friend_Add test; uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (const uint8_t *)"Gentoo", 7, &test); if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) { goto loop_top; } uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; tox_self_get_dht_id(toxes[pairs[i].tox1], dht_key); const uint16_t dht_port = tox_self_get_udp_port(toxes[pairs[i].tox1], nullptr); tox_bootstrap(toxes[pairs[i].tox2], "localhost", dht_port, dht_key, nullptr); ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, "failed to add friend error code: %i", test); } for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { num_f += tox_self_get_friend_list_size(toxes[i]); } ck_assert_msg(num_f == TCP_TEST_NUM_FRIENDS, "bad num friends: %u", num_f); uint16_t last_count = 0; while (true) { uint16_t counter = 0; for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { for (uint32_t j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j) { if (tox_friend_get_connection_status(toxes[i], j, nullptr) == TOX_CONNECTION_UDP) { ++counter; } } } if (counter != last_count) { printf("many_clients got to %u\n", counter); last_count = counter; } if (counter == TCP_TEST_NUM_FRIENDS * 2) { break; } for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { Tox_Err_Events_Iterate err = TOX_ERR_EVENTS_ITERATE_OK; Tox_Events *events = tox_events_iterate(toxes[i], true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); tox_dispatch_invoke(dispatch, events, toxes[i]); tox_events_free(events); } c_sleep(50); } tox_dispatch_free(dispatch); for (uint32_t i = 0; i < TCP_TEST_NUM_TOXES; ++i) { tox_kill(toxes[i]); } printf("test_many_clients succeeded, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_many_clients(); return 0; } c-toxcore-0.2.20/auto_tests/tox_new_test.c0000644060175106017510000000021014714247532016550 0ustar robin#include "../toxcore/tox.h" #include "../toxcore/ccompat.h" int main(void) { tox_kill(tox_new(nullptr, nullptr)); return 0; } c-toxcore-0.2.20/auto_tests/tox_strncasecmp_test.c0000644060175106017510000001233214714247532020311 0ustar robin#include #include #include "../testing/misc_tools.h" #include "check_compat.h" typedef enum { NEGATIVE, ZERO, POSITIVE } Comparison; static const char *comparison_str[] = { "NEGATIVE", "ZERO", "POSITIVE" }; static void verify(const char *s1, const char *s2, size_t n, Comparison expected) { int r = tox_strncasecmp(s1, s2, n); Comparison actual = r < 0 ? NEGATIVE : r == 0 ? ZERO : POSITIVE; ck_assert_msg(actual == expected, "tox_strncasecmp(\"%s\", \"%s\", %u) == %s, but expected %s.", s1, s2, (unsigned)n, comparison_str[actual], comparison_str[expected]); } static void test_general(void) { // empty strings are equal verify("", "", 100, ZERO); verify("", "", -1, ZERO); // ====== Same Case Test Cases ====== // equal strings with n=0 are equal verify("", "", 0, ZERO); verify("AAA", "AAA", 0, ZERO); // unequal strings with n=0 are equal verify("A", "B", 0, ZERO); verify("AAA", "BBB", 0, ZERO); verify("AAA", "BBBBBB", 0, ZERO); verify("AAAAAA", "BBB", 0, ZERO); // equal strings are equal verify("AAA", "AAA", 0, ZERO); verify("AAA", "AAA", 1, ZERO); verify("AAA", "AAA", 2, ZERO); verify("AAA", "AAA", 3, ZERO); verify("AAA", "AAA", 4, ZERO); verify("AAA", "AAA", 5, ZERO); verify("AAA", "AAA", -1, ZERO); verify("AAA", "AAAAAA", 0, ZERO); verify("AAA", "AAAAAA", 1, ZERO); verify("AAA", "AAAAAA", 2, ZERO); verify("AAA", "AAAAAA", 3, ZERO); verify("AAA", "AAAAAA", 4, NEGATIVE); verify("AAA", "AAAAAA", 5, NEGATIVE); verify("AAA", "AAAAAA", -1, NEGATIVE); verify("AAAAAA", "AAA", 0, ZERO); verify("AAAAAA", "AAA", 1, ZERO); verify("AAAAAA", "AAA", 2, ZERO); verify("AAAAAA", "AAA", 3, ZERO); verify("AAAAAA", "AAA", 4, POSITIVE); verify("AAAAAA", "AAA", 5, POSITIVE); verify("AAAAAA", "AAA", -1, POSITIVE); verify("I'm eating wafers and drinking tea.", "I'm eating wafers and drinking tea.", -1, ZERO); // unequal strings are equal only up to n verify("AAAB", "AAAA", 0, ZERO); verify("AAAB", "AAAA", 1, ZERO); verify("AAAB", "AAAA", 2, ZERO); verify("AAAB", "AAAA", 3, ZERO); verify("AAAB", "AAAA", 4, POSITIVE); verify("AAAB", "AAAA", 5, POSITIVE); verify("AAAB", "AAAA", -1, POSITIVE); verify("AAAA", "AAAB", 0, ZERO); verify("AAAA", "AAAB", 1, ZERO); verify("AAAA", "AAAB", 2, ZERO); verify("AAAA", "AAAB", 3, ZERO); verify("AAAA", "AAAB", 4, NEGATIVE); verify("AAAA", "AAAB", 5, NEGATIVE); verify("AAAA", "AAAB", -1, NEGATIVE); verify("The wafers are salty.", "The wafers are sweet.", 16, ZERO); verify("The wafers are salty.", "The wafers are sweet.", 17, NEGATIVE); verify("The wafers are salty.", "The wafers are sweet.", -1, NEGATIVE); // the comparison should stop at first mismatch verify("AAABA", "AAAAB", -1, POSITIVE); verify("AAAAB", "AAABA", -1, NEGATIVE); // ====== Different Case Test Cases ====== // equal strings with n=0 are equal verify("", "", 0, ZERO); verify("aaa", "AAA", 0, ZERO); // unequal strings with n=0 are equal verify("a", "B", 0, ZERO); verify("aaa", "BBB", 0, ZERO); verify("aaa", "BBBBBB", 0, ZERO); verify("aaaaaa", "BBB", 0, ZERO); // equal strings are equal verify("aaa", "AAA", 0, ZERO); verify("AAA", "aaa", 1, ZERO); verify("aaa", "AAA", 2, ZERO); verify("aaa", "AAA", 3, ZERO); verify("AAA", "aaa", 4, ZERO); verify("AAA", "aaa", 5, ZERO); verify("AAA", "aaa", -1, ZERO); verify("aaa", "AAAAAA", 0, ZERO); verify("AAA", "AAAaaa", 1, ZERO); verify("aaA", "aaaAAA", 2, ZERO); verify("AaA", "aAAAAA", 3, ZERO); verify("AAA", "AAAAAA", 4, NEGATIVE); verify("Aaa", "AAaaAA", 5, NEGATIVE); verify("AAA", "AAAAAa", -1, NEGATIVE); verify("AAAAAA", "aaa", 0, ZERO); verify("AAAaaa", "AAA", 1, ZERO); verify("aaaAAA", "aaA", 2, ZERO); verify("aAAAAA", "AaA", 3, ZERO); verify("AAAAAA", "AAA", 4, POSITIVE); verify("AAaaAA", "Aaa", 5, POSITIVE); verify("AAAAAa", "AAA", -1, POSITIVE); verify("I'm Eating Wafers And Drinking Tea.", "I'm eating wafers and drinking tea.", -1, ZERO); // unequal strings are equal only up to n verify("aaaB", "AAAA", 0, ZERO); verify("AaAB", "aAAA", 1, ZERO); verify("aAAB", "AaAA", 2, ZERO); verify("AAAB", "AAaA", 3, ZERO); verify("AAAB", "AAAA", 4, POSITIVE); verify("AAAb", "AAAA", 5, POSITIVE); verify("AAAB", "AAAa", -1, POSITIVE); verify("AAAA", "aaaB", 0, ZERO); verify("aAAA", "AaAB", 1, ZERO); verify("AaAA", "aAAB", 2, ZERO); verify("AAaA", "AAAB", 3, ZERO); verify("AAAA", "AAAB", 4, NEGATIVE); verify("AAAA", "AAAb", 5, NEGATIVE); verify("AAAa", "AAAB", -1, NEGATIVE); verify("The Wafers Are Salty.", "The wafers are sweet.", 16, ZERO); verify("The Wafers Are Salty.", "The wafers are sweet.", 17, NEGATIVE); verify("The Wafers Are Salty.", "The wafers are sweet.", -1, NEGATIVE); // the comparison should stop at first mismatch verify("aAaBA", "AAAAb", -1, POSITIVE); verify("AAAAb", "aAaBA", -1, NEGATIVE); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); test_general(); return 0; } c-toxcore-0.2.20/auto_tests/typing_test.c0000644060175106017510000000401614714247532016407 0ustar robin/* Tests that our typing notifications work. */ #include #include #include #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/tox.h" #include "../toxcore/util.h" #include "check_compat.h" typedef struct State { bool friend_is_typing; } State; #include "auto_test_support.h" static void typing_callback(const Tox_Event_Friend_Typing *event, void *user_data) { const AutoTox *autotox = (AutoTox *)user_data; State *state = (State *)autotox->state; //const uint32_t friend_number = tox_event_friend_typing_get_friend_number(event); const bool typing = tox_event_friend_typing_get_typing(event); state->friend_is_typing = typing; } static void test_typing(AutoTox *autotoxes) { time_t cur_time = time(nullptr); tox_events_callback_friend_typing(autotoxes[1].dispatch, &typing_callback); tox_self_set_typing(autotoxes[0].tox, 0, true, nullptr); do { iterate_all_wait(autotoxes, 2, 200); } while (!((State *)autotoxes[1].state)->friend_is_typing); ck_assert_msg(tox_friend_get_typing(autotoxes[1].tox, 0, nullptr) == 1, "tox_friend_get_typing should have returned true, but it didn't"); tox_self_set_typing(autotoxes[0].tox, 0, false, nullptr); do { iterate_all_wait(autotoxes, 2, 200); } while (((State *)autotoxes[1].state)->friend_is_typing); Tox_Err_Friend_Query err_t; ck_assert_msg(tox_friend_get_typing(autotoxes[1].tox, 0, &err_t) == 0, "tox_friend_get_typing should have returned false, but it didn't"); ck_assert_msg(err_t == TOX_ERR_FRIEND_QUERY_OK, "tox_friend_get_typing call did not return correct error"); printf("test_typing succeeded, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); } int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); Run_Auto_Options options = default_run_auto_options(); options.graph = GRAPH_LINEAR; run_auto_test(nullptr, 2, test_typing, sizeof(State), &options); return 0; } c-toxcore-0.2.20/auto_tests/version_test.c0000644060175106017510000000544514714247532016571 0ustar robin#include "../toxcore/tox.h" #include "check_compat.h" #define CHECK(major, minor, patch, expected) \ do_check(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH, \ major, minor, patch, \ TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch), expected) static void do_check(int lib_major, int lib_minor, int lib_patch, int cli_major, int cli_minor, int cli_patch, bool actual, bool expected) { ck_assert_msg(actual == expected, "Client version %d.%d.%d is%s compatible with library version %d.%d.%d, but it should%s be\n", cli_major, cli_minor, cli_patch, actual ? "" : " not", lib_major, lib_minor, lib_patch, expected ? "" : " not"); } #undef TOX_VERSION_MAJOR #undef TOX_VERSION_MINOR #undef TOX_VERSION_PATCH int main(void) { #define TOX_VERSION_MAJOR 0 #define TOX_VERSION_MINOR 0 #define TOX_VERSION_PATCH 4 // Tox versions from 0.0.* are only compatible with themselves. CHECK(0, 0, 0, false); CHECK(0, 0, 3, false); CHECK(0, 0, 4, true); CHECK(0, 0, 5, false); CHECK(1, 0, 4, false); #undef TOX_VERSION_MAJOR #undef TOX_VERSION_MINOR #undef TOX_VERSION_PATCH #define TOX_VERSION_MAJOR 0 #define TOX_VERSION_MINOR 1 #define TOX_VERSION_PATCH 4 // Tox versions from 0.1.* are only compatible with themselves or 0.1.<* CHECK(0, 0, 0, false); CHECK(0, 0, 4, false); CHECK(0, 0, 5, false); CHECK(0, 1, 0, true); CHECK(0, 1, 4, true); CHECK(0, 1, 5, false); CHECK(0, 2, 0, false); CHECK(0, 2, 4, false); CHECK(0, 2, 5, false); CHECK(1, 0, 0, false); CHECK(1, 0, 4, false); CHECK(1, 0, 5, false); CHECK(1, 1, 4, false); #undef TOX_VERSION_MAJOR #undef TOX_VERSION_MINOR #undef TOX_VERSION_PATCH #define TOX_VERSION_MAJOR 1 #define TOX_VERSION_MINOR 0 #define TOX_VERSION_PATCH 4 // Beyond 0.*.* Tox is comfortable with any lower version within their major CHECK(0, 0, 4, false); CHECK(1, 0, 0, true); CHECK(1, 0, 1, true); CHECK(1, 0, 4, true); CHECK(1, 0, 5, false); CHECK(1, 1, 0, false); CHECK(2, 0, 0, false); CHECK(2, 0, 4, false); #undef TOX_VERSION_MAJOR #undef TOX_VERSION_MINOR #undef TOX_VERSION_PATCH #define TOX_VERSION_MAJOR 1 #define TOX_VERSION_MINOR 1 #define TOX_VERSION_PATCH 4 CHECK(0, 0, 4, false); CHECK(1, 0, 0, true); CHECK(1, 0, 4, true); CHECK(1, 0, 5, true); CHECK(1, 1, 0, true); CHECK(1, 1, 1, true); CHECK(1, 1, 4, true); CHECK(1, 1, 5, false); CHECK(1, 2, 0, false); CHECK(1, 2, 4, false); CHECK(1, 2, 5, false); CHECK(2, 0, 0, false); CHECK(2, 1, 4, false); #undef TOX_VERSION_MAJOR #undef TOX_VERSION_MINOR #undef TOX_VERSION_PATCH return 0; } c-toxcore-0.2.20/azure-pipelines.yml0000644060175106017510000000075714714247532015347 0ustar robinpool: vmImage: "windows-2019" jobs: - job: "windows_msvc_conan" strategy: matrix: static: conan.shared: "False" shared: conan.shared: "True" steps: - bash: python -m pip install conan==1.59.0 - bash: git submodule update --init --recursive - bash: conan install -if _build -o with_tests=True -o shared=$(conan.shared) . - bash: CONAN_CPU_COUNT=50 CTEST_OUTPUT_ON_FAILURE=1 conan build -bf _build -if _build . || true c-toxcore-0.2.20/build/0000755060175106017510000000000014714247532012576 5ustar robinc-toxcore-0.2.20/build/Makefile.am0000644060175106017510000000103614714247532014632 0ustar robinbin_PROGRAMS = noinst_PROGRAMS = noinst_LTLIBRARIES = lib_LTLIBRARIES = noinst_bindir = $(top_builddir)/build EXTRA_DIST= if SET_SO_VERSION include ../so.version LT_LDFLAGS=-version-info $(CURRENT):$(REVISION):$(AGE) else LT_LDFLAGS=-avoid-version endif include ../toxcore/Makefile.inc include ../toxencryptsave/Makefile.inc include ../toxav/Makefile.inc include ../other/Makefile.inc include ../testing/Makefile.inc include ../other/bootstrap_daemon/src/Makefile.inc include ../auto_tests/Makefile.inc build-tests: $(check_PROGRAMS) c-toxcore-0.2.20/BUILD.bazel0000644060175106017510000000222114714247532013352 0ustar robinload("@rules_cc//cc:defs.bzl", "cc_library") load("//tools/project:build_defs.bzl", "project") project(license = "gpl3-https") genrule( name = "public_headers", srcs = [ "//c-toxcore/toxav:toxav.h", "//c-toxcore/toxcore:tox.h", "//c-toxcore/toxcore:tox_private.h", "//c-toxcore/toxencryptsave:toxencryptsave.h", ], outs = [ "tox/toxav.h", "tox/tox.h", "tox/tox_private.h", "tox/toxencryptsave.h", ], cmd = """ cp $(location //c-toxcore/toxav:toxav.h) $(GENDIR)/c-toxcore/tox/toxav.h cp $(location //c-toxcore/toxcore:tox.h) $(GENDIR)/c-toxcore/tox/tox.h cp $(location //c-toxcore/toxcore:tox_private.h) $(GENDIR)/c-toxcore/tox/tox_private.h cp $(location //c-toxcore/toxencryptsave:toxencryptsave.h) $(GENDIR)/c-toxcore/tox/toxencryptsave.h """, visibility = ["//visibility:public"], ) cc_library( name = "c-toxcore", hdrs = [":public_headers"], includes = ["."], visibility = ["//visibility:public"], deps = [ "//c-toxcore/toxav", "//c-toxcore/toxcore", "//c-toxcore/toxencryptsave", ], ) c-toxcore-0.2.20/CHANGELOG.md0000644060175106017510000052611214714247532013317 0ustar robin ## v0.2.20 ### Merged PRs: - [#2788](https://github.com/TokTok/c-toxcore/pull/2788) fix: Add missing free in dht_get_nodes_response event. - [#2786](https://github.com/TokTok/c-toxcore/pull/2786) cleanup: Fix all `-Wsign-compare` warnings. - [#2785](https://github.com/TokTok/c-toxcore/pull/2785) fix: wrong comment for closelist - [#2784](https://github.com/TokTok/c-toxcore/pull/2784) chore: lower cirrus ci timeout drastically - [#2783](https://github.com/TokTok/c-toxcore/pull/2783) fix: Return an error instead of crashing on nullptr args in NGC. - [#2782](https://github.com/TokTok/c-toxcore/pull/2782) fix(toxav): pass video bit rate as kbit - [#2780](https://github.com/TokTok/c-toxcore/pull/2780) chore: Add release-drafter github action. - [#2779](https://github.com/TokTok/c-toxcore/pull/2779) chore: Use toktok's cmp instead of upstream. - [#2778](https://github.com/TokTok/c-toxcore/pull/2778) cleanup: Sort apk/apt install commands in Dockerfiles. - [#2777](https://github.com/TokTok/c-toxcore/pull/2777) chore: Upgrade to FreeBSD 14.1 in cirrus build. - [#2772](https://github.com/TokTok/c-toxcore/pull/2772) fix: friend_connections leak on allocation failure. - [#2771](https://github.com/TokTok/c-toxcore/pull/2771) fix: events leak that can occur if allocation fails - [#2769](https://github.com/TokTok/c-toxcore/pull/2769) chore(ci): new minimum for all android versions is 21 - [#2768](https://github.com/TokTok/c-toxcore/pull/2768) fix: toxav rtp temp buffer allocation size was too large - [#2762](https://github.com/TokTok/c-toxcore/pull/2762) chore(cmake): set options changes as cache and with force - [#2761](https://github.com/TokTok/c-toxcore/pull/2761) chore: Fix CI - [#2757](https://github.com/TokTok/c-toxcore/pull/2757) fix: Use Opus in the CBR mode - [#2755](https://github.com/TokTok/c-toxcore/pull/2755) chore: Fix Circle CI build failing - [#2754](https://github.com/TokTok/c-toxcore/pull/2754) docs(toxav): fix docs of toxav.h - [#2751](https://github.com/TokTok/c-toxcore/pull/2751) chore(deps): bump golang.org/x/net from 0.17.0 to 0.23.0 in /other/bootstrap_daemon/websocket/websockify - [#2747](https://github.com/TokTok/c-toxcore/pull/2747) fix: Memory leak in the bootstrap daemon - [#2745](https://github.com/TokTok/c-toxcore/pull/2745) chore: Fix GitHub actions deprecation warnings - [#2717](https://github.com/TokTok/c-toxcore/pull/2717) cleanup: Remove useless if clause - [#2692](https://github.com/TokTok/c-toxcore/pull/2692) refactor: Make tox-bootstrapd use bool instead of int - [#2651](https://github.com/TokTok/c-toxcore/pull/2651) refactor: Make ToxAV independent of toxcore internals. ## v0.2.19 ### Merged PRs: - [#2744](https://github.com/TokTok/c-toxcore/pull/2744) docs: Document that group topic lock is default on. - [#2743](https://github.com/TokTok/c-toxcore/pull/2743) docs: Add missing param docs for callbacks. - [#2742](https://github.com/TokTok/c-toxcore/pull/2742) chore: Add cmake flag to disable unit tests. - [#2741](https://github.com/TokTok/c-toxcore/pull/2741) refactor: Don't expose Tox_System in the public API - [#2736](https://github.com/TokTok/c-toxcore/pull/2736) cleanup: A more descriptive error for group invite accept function - [#2735](https://github.com/TokTok/c-toxcore/pull/2735) chore: Small API doc fixes - [#2732](https://github.com/TokTok/c-toxcore/pull/2732) cleanup: event length naming inconsistencies - [#2731](https://github.com/TokTok/c-toxcore/pull/2731) cleanup: align group send err enum order - [#2729](https://github.com/TokTok/c-toxcore/pull/2729) cleanup: use typedef for private message ID's in callback - [#2728](https://github.com/TokTok/c-toxcore/pull/2728) refactor: Observers/ignored peers can now send and receive custom packets - [#2727](https://github.com/TokTok/c-toxcore/pull/2727) feat: add message IDs to private group messages - [#2726](https://github.com/TokTok/c-toxcore/pull/2726) refactor: Rename `out` parameters to `out_$something`. - [#2718](https://github.com/TokTok/c-toxcore/pull/2718) chore: Use a specific non-broken slimcc version. - [#2713](https://github.com/TokTok/c-toxcore/pull/2713) feat: Update and improve the Windows cross-compilation - [#2712](https://github.com/TokTok/c-toxcore/pull/2712) chore: Update github actions. - [#2710](https://github.com/TokTok/c-toxcore/pull/2710) docs: Update the list of CMake options - [#2709](https://github.com/TokTok/c-toxcore/pull/2709) refactor: Remove "mod" and "founder" from group API naming scheme - [#2708](https://github.com/TokTok/c-toxcore/pull/2708) docs: add the experimental api build option to INSTALL.md - [#2705](https://github.com/TokTok/c-toxcore/pull/2705) refactor: Rename Queries to Query to align with other enums. - [#2704](https://github.com/TokTok/c-toxcore/pull/2704) fix: Correct type for conference offline peer numbers. - [#2700](https://github.com/TokTok/c-toxcore/pull/2700) test: Add FreeBSD VM action on GitHub. - [#2699](https://github.com/TokTok/c-toxcore/pull/2699) test: Add pkgsrc build. - [#2698](https://github.com/TokTok/c-toxcore/pull/2698) chore: Only install tox_private.h on request. - [#2697](https://github.com/TokTok/c-toxcore/pull/2697) test: Build toxcore on NetBSD (VM). - [#2696](https://github.com/TokTok/c-toxcore/pull/2696) fix: save_compatibility_test failing on big-endian systems - [#2695](https://github.com/TokTok/c-toxcore/pull/2695) fix: Don't serve files from websockify. - [#2691](https://github.com/TokTok/c-toxcore/pull/2691) chore: Release 0.2.19 - [#2689](https://github.com/TokTok/c-toxcore/pull/2689) fix: Correctly pass extended public keys to group moderation code. - [#2686](https://github.com/TokTok/c-toxcore/pull/2686) chore: Compile libsodium reference implementation with compcert. - [#2685](https://github.com/TokTok/c-toxcore/pull/2685) cleanup: correct a few nullable annotations - [#2684](https://github.com/TokTok/c-toxcore/pull/2684) cleanup: Don't use `memcpy` to cast arbitrary `struct`s to `uint8_t[]`. - [#2683](https://github.com/TokTok/c-toxcore/pull/2683) fix: Pass array, not array pointer, to `memcmp`. - [#2682](https://github.com/TokTok/c-toxcore/pull/2682) cleanup: Never pass `void*` directly to `memcpy`. - [#2678](https://github.com/TokTok/c-toxcore/pull/2678) chore: Disable NGC saving by default, enable through Tox_Options. - [#2675](https://github.com/TokTok/c-toxcore/pull/2675) cleanup: Replace pointer arithmetic with explicit `&arr[i]`. - [#2672](https://github.com/TokTok/c-toxcore/pull/2672) refactor: Use `structs` for extended public/secret keys. - [#2671](https://github.com/TokTok/c-toxcore/pull/2671) refactor: Use tox rng to seed the keypair generation. - [#2666](https://github.com/TokTok/c-toxcore/pull/2666) cleanup: Small improvements found by PVS Studio. - [#2664](https://github.com/TokTok/c-toxcore/pull/2664) docs: Run prettier-markdown on markdown files. - [#2662](https://github.com/TokTok/c-toxcore/pull/2662) fix: Correct a few potential null derefs in bootstrap daemon. - [#2661](https://github.com/TokTok/c-toxcore/pull/2661) fix: Zero out stack-allocated secret key before return. - [#2660](https://github.com/TokTok/c-toxcore/pull/2660) fix: Add missing memunlock of local variable when it goes out of scope. - [#2659](https://github.com/TokTok/c-toxcore/pull/2659) cleanup: Simplify custom packet length check in NGC. - [#2658](https://github.com/TokTok/c-toxcore/pull/2658) refactor: Make prune_gc_sanctions_list more obviously correct. - [#2657](https://github.com/TokTok/c-toxcore/pull/2657) fix: Fix some false positive from PVS Studio. - [#2656](https://github.com/TokTok/c-toxcore/pull/2656) docs: Add static analysis tool list to README. - [#2655](https://github.com/TokTok/c-toxcore/pull/2655) cleanup: Check that WINXP macro exists before comparing it. - [#2652](https://github.com/TokTok/c-toxcore/pull/2652) refactor: Make tox mutex non-recursive. - [#2648](https://github.com/TokTok/c-toxcore/pull/2648) docs: Add more documentation to crypto_core. - [#2647](https://github.com/TokTok/c-toxcore/pull/2647) docs: Fix up doxyfile. - [#2645](https://github.com/TokTok/c-toxcore/pull/2645) refactor: Remove `Tox *` from `tox_dispatch`. - [#2644](https://github.com/TokTok/c-toxcore/pull/2644) refactor: Don't rely on tox_dispatch passing tox in tests. - [#2643](https://github.com/TokTok/c-toxcore/pull/2643) refactor: Use strong typedef for NGC peer id. - [#2642](https://github.com/TokTok/c-toxcore/pull/2642) chore: Use C++ mode for clang-tidy. - [#2640](https://github.com/TokTok/c-toxcore/pull/2640) refactor: Use strong `typedef` instead of `struct` for `Socket`. - [#2637](https://github.com/TokTok/c-toxcore/pull/2637) chore: Check that both gtest and gmock exist for tests. - [#2634](https://github.com/TokTok/c-toxcore/pull/2634) chore: Add some comments to the astyle config. - [#2629](https://github.com/TokTok/c-toxcore/pull/2629) chore: Reformat sources with astyle. - [#2626](https://github.com/TokTok/c-toxcore/pull/2626) chore: Rename C++ headers to .hh suffixes. - [#2624](https://github.com/TokTok/c-toxcore/pull/2624) test: Add slimcc compiler compatibility test. - [#2622](https://github.com/TokTok/c-toxcore/pull/2622) cleanup: Add more `const` where possible. - [#2621](https://github.com/TokTok/c-toxcore/pull/2621) cleanup: Remove implicit bool conversions. - [#2620](https://github.com/TokTok/c-toxcore/pull/2620) chore: Only check the bootstrap daemon checksum on release. - [#2617](https://github.com/TokTok/c-toxcore/pull/2617) cleanup: Further `#include` cleanups. - [#2614](https://github.com/TokTok/c-toxcore/pull/2614) cleanup: Use Bazel modules to enforce proper `#include` hygiene. - [#2612](https://github.com/TokTok/c-toxcore/pull/2612) refactor: Move pack/unpack `IP_Port` from DHT into network module. - [#2611](https://github.com/TokTok/c-toxcore/pull/2611) chore: Really fix coverage docker image build. - [#2610](https://github.com/TokTok/c-toxcore/pull/2610) chore: Fix post-submit coverage image. - [#2609](https://github.com/TokTok/c-toxcore/pull/2609) fix: partially fix a bug that prevented group part messages from sending - [#2605](https://github.com/TokTok/c-toxcore/pull/2605) fix: Don't use `memcmp` to compare `IP_Port`s. - [#2604](https://github.com/TokTok/c-toxcore/pull/2604) chore: Fix rpm build; add a CI check for it. - [#2603](https://github.com/TokTok/c-toxcore/pull/2603) chore: Speed up docker builds a bit by reducing layer count. - [#2602](https://github.com/TokTok/c-toxcore/pull/2602) cleanup: Add `const` where possible in auto tests. - [#2601](https://github.com/TokTok/c-toxcore/pull/2601) fix: a few off by one errors in group autotests - [#2598](https://github.com/TokTok/c-toxcore/pull/2598) refactor: Rename `system_{memory,...}` to `os_{memory,...}`. - [#2597](https://github.com/TokTok/c-toxcore/pull/2597) test: Add goblint static analyser. - [#2594](https://github.com/TokTok/c-toxcore/pull/2594) cleanup: Use `memzero(x, s)` instead of `memset(x, 0, s)`. - [#2593](https://github.com/TokTok/c-toxcore/pull/2593) cleanup: Use explicit 0 instead of `PACKET_ID_PADDING`. - [#2592](https://github.com/TokTok/c-toxcore/pull/2592) cleanup: Remove all uses of `SIZEOF_VLA`. - [#2591](https://github.com/TokTok/c-toxcore/pull/2591) cleanup: Expand the `Tox_Options` accessor macros. - [#2590](https://github.com/TokTok/c-toxcore/pull/2590) test: Add a simple new/delete test for Tox. - [#2588](https://github.com/TokTok/c-toxcore/pull/2588) cleanup: Remove plan9 support. - [#2587](https://github.com/TokTok/c-toxcore/pull/2587) cleanup: Add comment after every `#endif`. - [#2583](https://github.com/TokTok/c-toxcore/pull/2583) test: Fix comment I broke in the events test PR. - [#2582](https://github.com/TokTok/c-toxcore/pull/2582) cleanup: Rename group to conference in groupav documentation. - [#2581](https://github.com/TokTok/c-toxcore/pull/2581) cleanup: Ensure handler params are named after callback params. - [#2580](https://github.com/TokTok/c-toxcore/pull/2580) cleanup: Minor cleanup of event unpack code. - [#2578](https://github.com/TokTok/c-toxcore/pull/2578) refactor: Allow NULL pointers for byte arrays in events. - [#2577](https://github.com/TokTok/c-toxcore/pull/2577) refactor: Add common msgpack array packer with callback. - [#2576](https://github.com/TokTok/c-toxcore/pull/2576) cleanup: make some improvements to group moderation test - [#2575](https://github.com/TokTok/c-toxcore/pull/2575) refactor: Pass `this` pointer as first param to s11n callbacks. - [#2573](https://github.com/TokTok/c-toxcore/pull/2573) cleanup: skip a do_gc iteration before removing peers marked for deletion - [#2572](https://github.com/TokTok/c-toxcore/pull/2572) cleanup: Remove `bin_pack_{new,free}`. - [#2568](https://github.com/TokTok/c-toxcore/pull/2568) feat: Add dht_get_nodes_response event to the events system. - [#2567](https://github.com/TokTok/c-toxcore/pull/2567) refactor: Use enum-specific pack functions for enum values. - [#2566](https://github.com/TokTok/c-toxcore/pull/2566) cleanup: Remove empty test doing nothing. - [#2565](https://github.com/TokTok/c-toxcore/pull/2565) refactor: Factor out union pack switch from event packer. - [#2564](https://github.com/TokTok/c-toxcore/pull/2564) cleanup: Move the 2-element array pack out of individual events. - [#2563](https://github.com/TokTok/c-toxcore/pull/2563) test: Add printf log statement to group_moderation_test. - [#2562](https://github.com/TokTok/c-toxcore/pull/2562) chore: add clangd files to .gitignore - [#2561](https://github.com/TokTok/c-toxcore/pull/2561) refactor: Move file streaming test to its own file. - [#2560](https://github.com/TokTok/c-toxcore/pull/2560) fix(ci): window builds now build in parallel - [#2559](https://github.com/TokTok/c-toxcore/pull/2559) refactor: Migrate auto_tests to new events API. - [#2557](https://github.com/TokTok/c-toxcore/pull/2557) test: Add C++ classes wrapping system interfaces. - [#2555](https://github.com/TokTok/c-toxcore/pull/2555) fix: Remove fatal error for non-erroneous case - [#2554](https://github.com/TokTok/c-toxcore/pull/2554) fix: Make all the fuzzers work again, and add a test for protodump. - [#2552](https://github.com/TokTok/c-toxcore/pull/2552) fix: Make sure there's enough space for CONSUME1 in fuzzers. - [#2551](https://github.com/TokTok/c-toxcore/pull/2551) chore: Move from gcov to llvm source-based coverage. - [#2549](https://github.com/TokTok/c-toxcore/pull/2549) fix: issues with packet broadcast error reporting - [#2547](https://github.com/TokTok/c-toxcore/pull/2547) test: Add fuzz tests to the coverage run. - [#2545](https://github.com/TokTok/c-toxcore/pull/2545) refactor: Use `operator==` for equality tests of `Node_format`. - [#2543](https://github.com/TokTok/c-toxcore/pull/2543) refactor(test): Slightly nicer C++ interface to tox Random. - [#2542](https://github.com/TokTok/c-toxcore/pull/2542) refactor: packet broadcast functions now return errors - [#2541](https://github.com/TokTok/c-toxcore/pull/2541) fix: don't pass garbage data buffer to packet send functions - [#2540](https://github.com/TokTok/c-toxcore/pull/2540) cleanup: Make group packet entry creation less error-prone - [#2539](https://github.com/TokTok/c-toxcore/pull/2539) refactor: Minor refactoring of get_close_nodes functions. - [#2538](https://github.com/TokTok/c-toxcore/pull/2538) refactor: Factor out malloc+memcpy into memdup. - [#2536](https://github.com/TokTok/c-toxcore/pull/2536) cleanup: Some more test cleanups, removing overly smart code. - [#2531](https://github.com/TokTok/c-toxcore/pull/2531) test: Add more unit tests for `add_to_list`. - [#2530](https://github.com/TokTok/c-toxcore/pull/2530) refactor: Assign malloc return to a local variable first. - [#2529](https://github.com/TokTok/c-toxcore/pull/2529) test: Add "infer" CI check to github, remove from circle. - [#2527](https://github.com/TokTok/c-toxcore/pull/2527) cleanup: Add Toxav alias for ToxAV. - [#2526](https://github.com/TokTok/c-toxcore/pull/2526) cleanup: Make Tox_Options a typedef. - [#2525](https://github.com/TokTok/c-toxcore/pull/2525) cleanup: Add dynamically derived array sizes to the API. - [#2524](https://github.com/TokTok/c-toxcore/pull/2524) cleanup: Add explicit array sizes to toxencryptsave. - [#2523](https://github.com/TokTok/c-toxcore/pull/2523) cleanup: Move `tox_get_system` out of the public API. - [#2522](https://github.com/TokTok/c-toxcore/pull/2522) cleanup: Make setters take non-const `Tox *`. - [#2521](https://github.com/TokTok/c-toxcore/pull/2521) cleanup: Make array params in toxav `[]` instead of `*`. - [#2520](https://github.com/TokTok/c-toxcore/pull/2520) cleanup: Mark arrays in the tox API as `[]` instead of `*`. - [#2519](https://github.com/TokTok/c-toxcore/pull/2519) refactor: Align group message sending with other send functions. - [#2518](https://github.com/TokTok/c-toxcore/pull/2518) cleanup: Add typedefs for public API int identifiers. - [#2517](https://github.com/TokTok/c-toxcore/pull/2517) chore: Spellcheck tox-bootstrapd - [#2516](https://github.com/TokTok/c-toxcore/pull/2516) chore: Remove settings.yml in favour of hs-github-tools. - [#2515](https://github.com/TokTok/c-toxcore/pull/2515) chore: Use GPL license with https. - [#2513](https://github.com/TokTok/c-toxcore/pull/2513) chore: Add fetch-sha256 script to update bootstrap node hash. - [#2512](https://github.com/TokTok/c-toxcore/pull/2512) cleanup: Move all vptr-to-ptr casts to the beginning of a function. - [#2510](https://github.com/TokTok/c-toxcore/pull/2510) cleanup: Use github actions matrix to simplify CI. - [#2509](https://github.com/TokTok/c-toxcore/pull/2509) fix: Use QueryPerformanceCounter on windows for monotonic time. - [#2508](https://github.com/TokTok/c-toxcore/pull/2508) chore: Add `net_(new|kill)_strerror` to cppcheck's allocators. - [#2507](https://github.com/TokTok/c-toxcore/pull/2507) cleanup: Run clang-tidy on headers, as well. - [#2506](https://github.com/TokTok/c-toxcore/pull/2506) cleanup: Make TCP connection failures a warning instead of error. - [#2505](https://github.com/TokTok/c-toxcore/pull/2505) cleanup: Make all .c files include the headers they need. - [#2504](https://github.com/TokTok/c-toxcore/pull/2504) cleanup: Upgrade cppcheck, fix some warnings. - [#2503](https://github.com/TokTok/c-toxcore/pull/2503) cleanup: Upgrade to clang-tidy-17 and fix some warnings. - [#2502](https://github.com/TokTok/c-toxcore/pull/2502) chore: Use `pkg_search_module` directly in cmake. - [#2501](https://github.com/TokTok/c-toxcore/pull/2501) chore: Add `IMPORTED_TARGET` to pkg-config packages. - [#2499](https://github.com/TokTok/c-toxcore/pull/2499) cleanup: Use target_link_libraries directly in cmake. - [#2498](https://github.com/TokTok/c-toxcore/pull/2498) chore: Simplify msvc build using vcpkg. - [#2497](https://github.com/TokTok/c-toxcore/pull/2497) cleanup: Remove NaCl support. - [#2494](https://github.com/TokTok/c-toxcore/pull/2494) fix: unpack enum function names in event impl generator - [#2493](https://github.com/TokTok/c-toxcore/pull/2493) chore: Disable targets for cross-compilation. - [#2491](https://github.com/TokTok/c-toxcore/pull/2491) chore: Build a docker image with coverage info in it. - [#2490](https://github.com/TokTok/c-toxcore/pull/2490) cleanup: Some portability/warning fixes for Windows builds. - [#2488](https://github.com/TokTok/c-toxcore/pull/2488) fix: Correct a use-after-free and fix some memory leaks. - [#2487](https://github.com/TokTok/c-toxcore/pull/2487) refactor: Change all enum-like `#define` sequences into enums. - [#2486](https://github.com/TokTok/c-toxcore/pull/2486) refactor: Change the `TCP_PACKET_*` defines into an enum. - [#2485](https://github.com/TokTok/c-toxcore/pull/2485) refactor: event generation tool for reorder pr - [#2484](https://github.com/TokTok/c-toxcore/pull/2484) chore: Fix make_single_file to support core-only. - [#2481](https://github.com/TokTok/c-toxcore/pull/2481) chore: Update github actions `uses`. - [#2480](https://github.com/TokTok/c-toxcore/pull/2480) feat: add ngc related unpack functions - [#2479](https://github.com/TokTok/c-toxcore/pull/2479) feat: Add `to_string` functions for all public enums. - [#2477](https://github.com/TokTok/c-toxcore/pull/2477) test: add real timeout test - [#2476](https://github.com/TokTok/c-toxcore/pull/2476) chore: Move s390x build to post-merge. - [#2475](https://github.com/TokTok/c-toxcore/pull/2475) refactor: Give `enum-from-int` functions the ability to report errors. - [#2474](https://github.com/TokTok/c-toxcore/pull/2474) cleanup: Remove test net support. - [#2472](https://github.com/TokTok/c-toxcore/pull/2472) feat: Enable ubsan on bootstrap nodes. - [#2470](https://github.com/TokTok/c-toxcore/pull/2470) test: Add check-c run to bazel build. - [#2468](https://github.com/TokTok/c-toxcore/pull/2468) fix(test): tests use ipv6 by default, even with USE_IPV6 set to 0 - [#2466](https://github.com/TokTok/c-toxcore/pull/2466) cleanup: Make group saving/loading more forgiving with data errors - [#2465](https://github.com/TokTok/c-toxcore/pull/2465) refactor: replace memset with a loop - [#2459](https://github.com/TokTok/c-toxcore/pull/2459) fix: Enable debug flag for ubsan. - [#2458](https://github.com/TokTok/c-toxcore/pull/2458) fix: also Install header for private/experimental API functions with autotools - [#2456](https://github.com/TokTok/c-toxcore/pull/2456) docs: Remove defunct IRC channel from README.md - [#2454](https://github.com/TokTok/c-toxcore/pull/2454) fix: memory leaks - [#2453](https://github.com/TokTok/c-toxcore/pull/2453) refactor: Install header for private/experimental API functions - [#2452](https://github.com/TokTok/c-toxcore/pull/2452) refactor: replace DEFAULT_TCP_RELAY_PORTS_COUNT with a compile-time calculation - [#2451](https://github.com/TokTok/c-toxcore/pull/2451) cleanup: clarify disabling of static assert checks - [#2449](https://github.com/TokTok/c-toxcore/pull/2449) cleanup: replace tabs with spaces - [#2448](https://github.com/TokTok/c-toxcore/pull/2448) feat: group connection queries now return our own connection type - [#2447](https://github.com/TokTok/c-toxcore/pull/2447) fix: Docker tox-bootstrapd hash update failing when using BuildKit - [#2446](https://github.com/TokTok/c-toxcore/pull/2446) feat: Add groupchat API function that returns an IP address string for a peer - [#2442](https://github.com/TokTok/c-toxcore/pull/2442) perf: Slightly reduce bandwidth usage when there are few nodes. - [#2439](https://github.com/TokTok/c-toxcore/pull/2439) test: Make esp32 build actually try to instantiate tox. - [#2438](https://github.com/TokTok/c-toxcore/pull/2438) cleanup: Remove explicit layering_check feature. - [#2437](https://github.com/TokTok/c-toxcore/pull/2437) chore: Upgrade sonar-scan jvm to java 17. - [#2436](https://github.com/TokTok/c-toxcore/pull/2436) fix: Add missing `htons` call when adding configured TCP relay. - [#2434](https://github.com/TokTok/c-toxcore/pull/2434) chore: Cancel old PR builds on docker and sonar-scan workflows. - [#2432](https://github.com/TokTok/c-toxcore/pull/2432) chore: Use C99 on MSVC instead of C11. - [#2430](https://github.com/TokTok/c-toxcore/pull/2430) chore: Retry freebsd tests 2 times. - [#2429](https://github.com/TokTok/c-toxcore/pull/2429) test: Add an s390x build (on alpine) for CI. - [#2428](https://github.com/TokTok/c-toxcore/pull/2428) chore: Add a compcert docker run script. - [#2427](https://github.com/TokTok/c-toxcore/pull/2427) cleanup: Use tcc docker image for CI. - [#2424](https://github.com/TokTok/c-toxcore/pull/2424) fix: Fix memory leak in the error path of loading savedata. - [#2420](https://github.com/TokTok/c-toxcore/pull/2420) refactor: Use Bin_Pack for packing Node_format. - [#2416](https://github.com/TokTok/c-toxcore/pull/2416) chore: Add more logging to loading conferences from savedata. - [#2415](https://github.com/TokTok/c-toxcore/pull/2415) refactor: Add a `bin_unpack_bin_max` for max-length arrays. - [#2414](https://github.com/TokTok/c-toxcore/pull/2414) fix: inversed return values - [#2413](https://github.com/TokTok/c-toxcore/pull/2413) cleanup: Fix GCC compatibility. - [#2408](https://github.com/TokTok/c-toxcore/pull/2408) fix: Ensure we have allocators available for the error paths. - [#2407](https://github.com/TokTok/c-toxcore/pull/2407) cleanup: Remove redundant `-DSODIUM_EXPORT` from definitions. - [#2406](https://github.com/TokTok/c-toxcore/pull/2406) cleanup: Fix a few more clang-tidy warnings. - [#2405](https://github.com/TokTok/c-toxcore/pull/2405) cleanup: Fix a few more clang-tidy warnings. - [#2404](https://github.com/TokTok/c-toxcore/pull/2404) cleanup: Enforce stricter identifier naming using clang-tidy. - [#2396](https://github.com/TokTok/c-toxcore/pull/2396) chore: Add devcontainer setup for codespaces. - [#2393](https://github.com/TokTok/c-toxcore/pull/2393) refactor: Add `mem` module to allow tests to override allocators. - [#2392](https://github.com/TokTok/c-toxcore/pull/2392) refactor: Make event dispatch ordered by receive time. - [#2391](https://github.com/TokTok/c-toxcore/pull/2391) docs: Fix doxygen config and remove some redundant comments. - [#2390](https://github.com/TokTok/c-toxcore/pull/2390) chore: Fix the Android CI job - [#2389](https://github.com/TokTok/c-toxcore/pull/2389) fix: Add missing `#include `. - [#2388](https://github.com/TokTok/c-toxcore/pull/2388) chore: Add missing module dependencies. - [#2384](https://github.com/TokTok/c-toxcore/pull/2384) feat: increase NGC lossy custom packet size - [#2383](https://github.com/TokTok/c-toxcore/pull/2383) fix: add missing ngc constants getter declarations and definitions - [#2381](https://github.com/TokTok/c-toxcore/pull/2381) fix: incorrect documentation - [#2380](https://github.com/TokTok/c-toxcore/pull/2380) feat: allow for larger incoming NGC packets - [#2371](https://github.com/TokTok/c-toxcore/pull/2371) docs: fix group_peer_exit_cb - [#2370](https://github.com/TokTok/c-toxcore/pull/2370) fix: behaviour of group api function - [#2369](https://github.com/TokTok/c-toxcore/pull/2369) fix: flaky tcp test - [#2367](https://github.com/TokTok/c-toxcore/pull/2367) fix: fuzz support for TCP server - [#2364](https://github.com/TokTok/c-toxcore/pull/2364) fix: potential endless loop under extremely high load - [#2362](https://github.com/TokTok/c-toxcore/pull/2362) test: enable tcp relay for bootstrap fuzzing - [#2361](https://github.com/TokTok/c-toxcore/pull/2361) fix: resolve_bootstrap_node() not checking net_getipport() returned count correctly - [#2357](https://github.com/TokTok/c-toxcore/pull/2357) feat: get the number of close dht nodes with announce/store support - [#2355](https://github.com/TokTok/c-toxcore/pull/2355) fix: group custom packet size limits - [#2354](https://github.com/TokTok/c-toxcore/pull/2354) fix: DHTBootstrap should always respond to version packets with toxcore version - [#2351](https://github.com/TokTok/c-toxcore/pull/2351) fix: Increase max group message length by four bytes - [#2348](https://github.com/TokTok/c-toxcore/pull/2348) refactor: Make some improvements to how often/when we announce a group - [#2341](https://github.com/TokTok/c-toxcore/pull/2341) fix: #1144 by forcing misc_tools to be a static lib - [#2340](https://github.com/TokTok/c-toxcore/pull/2340) fix: missing net to host conversion of port in logging in group_chat.c - [#2339](https://github.com/TokTok/c-toxcore/pull/2339) fix: missing net to host conversion of port in logging - [#2338](https://github.com/TokTok/c-toxcore/pull/2338) fix: bug causing friend group invites to sometimes fail & improve logging - [#2333](https://github.com/TokTok/c-toxcore/pull/2333) docs: Update README for bootstrap node docker - [#2329](https://github.com/TokTok/c-toxcore/pull/2329) refactor: extract each case in handle packet in messenger - [#2327](https://github.com/TokTok/c-toxcore/pull/2327) fix: unlock correct dht_friend - [#2325](https://github.com/TokTok/c-toxcore/pull/2325) fix: Remove cmake cache files after copying to container build directory - [#2323](https://github.com/TokTok/c-toxcore/pull/2323) docs: Update README.md to include cmp submodule info - [#2318](https://github.com/TokTok/c-toxcore/pull/2318) chore: disable warning about pre C99 code - [#2317](https://github.com/TokTok/c-toxcore/pull/2317) Refactor: Extract shared key cache into separate file - [#2311](https://github.com/TokTok/c-toxcore/pull/2311) cleanup: make it more clear that assert and uint32_t increment both only exist if NDEBUG is not defined - [#2291](https://github.com/TokTok/c-toxcore/pull/2291) test: Add a protocol dump test to generate initial fuzzer input. - [#2271](https://github.com/TokTok/c-toxcore/pull/2271) chore: Migrate from Appveyor to Azure Pipelines - [#2269](https://github.com/TokTok/c-toxcore/pull/2269) feat: Merge the remainder of the new groupchats implementation - [#2203](https://github.com/TokTok/c-toxcore/pull/2203) refactor: Store time in Mono_Time in milliseconds. - [#1944](https://github.com/TokTok/c-toxcore/pull/1944) chore: tox_new() should return null when savedata loading fails ### Closed issues: - [#2739](https://github.com/TokTok/c-toxcore/issues/2739) Tox_Options.operating_system is not clear about it being an experimental option - [#2734](https://github.com/TokTok/c-toxcore/issues/2734) error compiling on fedora - [#2649](https://github.com/TokTok/c-toxcore/issues/2649) create_extended_keypair should use Random and be made deterministic for fuzzing - [#2462](https://github.com/TokTok/c-toxcore/issues/2462) Fix code scanning alert - Uncontrolled data used in path expression - [#2358](https://github.com/TokTok/c-toxcore/issues/2358) resolve_bootstrap_node assert hit - [#2352](https://github.com/TokTok/c-toxcore/issues/2352) SEGV after infinite loop retrying proxy_socks5_read_connection_response - [#2335](https://github.com/TokTok/c-toxcore/issues/2335) ipv6 disabled on kernel cmdline disrupts Tox = most tests fail - [#2303](https://github.com/TokTok/c-toxcore/issues/2303) Add new group chats events to tox_events and tox_dispatch modules. - [#2302](https://github.com/TokTok/c-toxcore/issues/2302) Run strong fuzz tests against NGC - [#2301](https://github.com/TokTok/c-toxcore/issues/2301) Implement NGC save/load in hs-toxcore and run round-trip tests against c-toxcore - [#2192](https://github.com/TokTok/c-toxcore/issues/2192) Provide official signed release tarballs - [#2118](https://github.com/TokTok/c-toxcore/issues/2118) Add a private "get mono_time" API to `tox_private.h` and use it in auto_tests. - [#2029](https://github.com/TokTok/c-toxcore/issues/2029) Migrate all auto tests to the events API. - [#2014](https://github.com/TokTok/c-toxcore/issues/2014) Add sodium autotools CI build - [#1144](https://github.com/TokTok/c-toxcore/issues/1144) DHT_bootstrap should not link against misc_tools ## v0.2.18 ### Merged PRs: - [#2300](https://github.com/TokTok/c-toxcore/pull/2300) chore: Release 0.2.18 - [#2299](https://github.com/TokTok/c-toxcore/pull/2299) fix: remove the assert because buffer can be larger than UINT16_MAX. - [#2297](https://github.com/TokTok/c-toxcore/pull/2297) cleanup: remove unused field last_seen from Onion_Friend - [#2289](https://github.com/TokTok/c-toxcore/pull/2289) test: Add a Null_System used in toxsave_harness. - [#2288](https://github.com/TokTok/c-toxcore/pull/2288) test: enable additional sanitizers for fuzzing - [#2287](https://github.com/TokTok/c-toxcore/pull/2287) fix: Don't allow onion paths to be built from real friends. - [#2285](https://github.com/TokTok/c-toxcore/pull/2285) test: Don't abort fuzz test when tox_new fails. - [#2284](https://github.com/TokTok/c-toxcore/pull/2284) refactor: Move crypto utilities from util to crypto_core. - [#2283](https://github.com/TokTok/c-toxcore/pull/2283) fix: Allow onion paths to be built from more random nodes. - [#2282](https://github.com/TokTok/c-toxcore/pull/2282) fix: Fix potential array out-of-bounds in DHT onion path building. - [#2281](https://github.com/TokTok/c-toxcore/pull/2281) cleanup: Avoid goto in msi.c. - [#2280](https://github.com/TokTok/c-toxcore/pull/2280) test: Improve test hermeticity by using local TCP relay. - [#2279](https://github.com/TokTok/c-toxcore/pull/2279) test: Enable fuzzing for TCP. - [#2277](https://github.com/TokTok/c-toxcore/pull/2277) refactor: Avoid `static_cast` in `Fuzz_System` functions. - [#2275](https://github.com/TokTok/c-toxcore/pull/2275) chore: Downgrade C++ version to 17 - [#2273](https://github.com/TokTok/c-toxcore/pull/2273) fix: Really fix overrun added in e49a477a - [#2272](https://github.com/TokTok/c-toxcore/pull/2272) fix: Add missing return on error - [#2270](https://github.com/TokTok/c-toxcore/pull/2270) test: Improve error messages in toxav_basic_test. - [#2266](https://github.com/TokTok/c-toxcore/pull/2266) fix: Fixed leak and overrun added in e49a477a - [#2263](https://github.com/TokTok/c-toxcore/pull/2263) chore: Upgrade to C++20 in CMake build. - [#2261](https://github.com/TokTok/c-toxcore/pull/2261) refactor: Protect array unpacking against invalid lengths. - [#2258](https://github.com/TokTok/c-toxcore/pull/2258) refactor: Rename announce functions into their own namespace. - [#2257](https://github.com/TokTok/c-toxcore/pull/2257) fix: Format IP as string again in error log. - [#2255](https://github.com/TokTok/c-toxcore/pull/2255) fix: Fix a stack overflow triggered by small DHT packets. - [#2251](https://github.com/TokTok/c-toxcore/pull/2251) chore: Add MISRA-2012 check using cppcheck's misra addon. - [#2250](https://github.com/TokTok/c-toxcore/pull/2250) cleanup: remove populate_path_nodes_tcp - [#2249](https://github.com/TokTok/c-toxcore/pull/2249) test: Improve stability of forwarding_test. - [#2248](https://github.com/TokTok/c-toxcore/pull/2248) refactor: Use a struct for the `ip_ntoa` buffer. - [#2246](https://github.com/TokTok/c-toxcore/pull/2246) fix: Don't crash if RNG init failed. - [#2244](https://github.com/TokTok/c-toxcore/pull/2244) refactor: Allow NULL logger; make it no-op in NDEBUG. - [#2243](https://github.com/TokTok/c-toxcore/pull/2243) chore: Add initial ESP32 docker build. - [#2242](https://github.com/TokTok/c-toxcore/pull/2242) cleanup: Use `static_assert` instead of `assert` where possible. - [#2240](https://github.com/TokTok/c-toxcore/pull/2240) chore(deps): Use upstream cmp directly instead of our fork. - [#2238](https://github.com/TokTok/c-toxcore/pull/2238) cleanup: Make `*_free` and `kill_*` functions nullable. - [#2236](https://github.com/TokTok/c-toxcore/pull/2236) chore: Add dependabot config. - [#2234](https://github.com/TokTok/c-toxcore/pull/2234) test: Add more functionality to the bootstrap fuzz harness. - [#2233](https://github.com/TokTok/c-toxcore/pull/2233) cleanup: Replace a series of `if` statements with a `switch`. - [#2232](https://github.com/TokTok/c-toxcore/pull/2232) test: Add fuzzer support functions for internal toxcore objects. - [#2230](https://github.com/TokTok/c-toxcore/pull/2230) feat: Merge group announce portion of new groupchats implementation - [#2229](https://github.com/TokTok/c-toxcore/pull/2229) cleanup: Remove layers in the cmake build. - [#2228](https://github.com/TokTok/c-toxcore/pull/2228) chore: Fix path to fuzzer binaries in clusterfuzz build. - [#2227](https://github.com/TokTok/c-toxcore/pull/2227) cleanup: Disallow stack frames of over 9000 bytes. - [#2225](https://github.com/TokTok/c-toxcore/pull/2225) fix: fix typo in git command in INSTALL.md - [#2224](https://github.com/TokTok/c-toxcore/pull/2224) cleanup: Add include for assert.h for the fuzzing build. - [#2223](https://github.com/TokTok/c-toxcore/pull/2223) chore: Add `uint8_t` version of `bin_pack` for numbers. - [#2219](https://github.com/TokTok/c-toxcore/pull/2219) refactor: Rename bin_pack/unpack functions the same as cmp funcs. - [#2217](https://github.com/TokTok/c-toxcore/pull/2217) cleanup: Add Network object parameter for addr_resolve. - [#2214](https://github.com/TokTok/c-toxcore/pull/2214) cleanup: Remove all uses of `TOX_*_MAX_SIZE` macros. - [#2213](https://github.com/TokTok/c-toxcore/pull/2213) cleanup: Remove unused random_testing program. - [#2212](https://github.com/TokTok/c-toxcore/pull/2212) cleanup: Expand `CONST_FUNCTION` and remove the macro. - [#2211](https://github.com/TokTok/c-toxcore/pull/2211) cleanup: Move definitions of tox_private.h functions to tox_private.c. - [#2210](https://github.com/TokTok/c-toxcore/pull/2210) chore: Clone submodules in clusterfuzzlite Dockerfile. - [#2208](https://github.com/TokTok/c-toxcore/pull/2208) chore: Remove valgrind build. - [#2206](https://github.com/TokTok/c-toxcore/pull/2206) feat: Allow overriding mono_time in tox_new. - [#2204](https://github.com/TokTok/c-toxcore/pull/2204) chore: Support producing shared libraries on Windows - [#2202](https://github.com/TokTok/c-toxcore/pull/2202) cleanup: Avoid name clash between struct field and function. - [#2201](https://github.com/TokTok/c-toxcore/pull/2201) docs: Add information regarding git submodules, cmp to INSTALL.md - [#2200](https://github.com/TokTok/c-toxcore/pull/2200) cleanup: Add more null checks in `tox_new`. - [#2199](https://github.com/TokTok/c-toxcore/pull/2199) cleanup: Mark Mono_Time const where possible. - [#2196](https://github.com/TokTok/c-toxcore/pull/2196) test: Remove save_load_test from autotools build. - [#2195](https://github.com/TokTok/c-toxcore/pull/2195) fix: Correct calculation of packet sent time - [#2193](https://github.com/TokTok/c-toxcore/pull/2193) perf: Make time move a lot faster in fuzzing runs. - [#2190](https://github.com/TokTok/c-toxcore/pull/2190) feat: Add support for custom random number generator. - [#2189](https://github.com/TokTok/c-toxcore/pull/2189) chore: Add third_party to toxcore-sources docker image. - [#2188](https://github.com/TokTok/c-toxcore/pull/2188) cleanup: Make addr_resolve a private function. - [#2187](https://github.com/TokTok/c-toxcore/pull/2187) test: Add DHT and tox_events fuzz tests to the cmake build. - [#2186](https://github.com/TokTok/c-toxcore/pull/2186) cleanup: Use `_Static_assert` in gcc/clang. - [#2184](https://github.com/TokTok/c-toxcore/pull/2184) test: Add some support functions to make writing fuzzers easier. - [#2183](https://github.com/TokTok/c-toxcore/pull/2183) test: Enable more tests for msan. - [#2182](https://github.com/TokTok/c-toxcore/pull/2182) test: Improve stability of tox_many_tcp_test. - [#2177](https://github.com/TokTok/c-toxcore/pull/2177) feat: Add support for overriding network functions. - [#2176](https://github.com/TokTok/c-toxcore/pull/2176) test: try to save the fuzzed save file again - [#2175](https://github.com/TokTok/c-toxcore/pull/2175) refactor: Use cmp instead of msgpack-c for events packing. - [#2173](https://github.com/TokTok/c-toxcore/pull/2173) chore: Use "master" as the branch in toktok-fuzzer. - [#2170](https://github.com/TokTok/c-toxcore/pull/2170) test: Add fuzzer tests to the bazel build. - [#2169](https://github.com/TokTok/c-toxcore/pull/2169) feat: Merge moderation portion of new groupchats codebase - [#2167](https://github.com/TokTok/c-toxcore/pull/2167) cleanup: Reduce scope of array-typed variables where possible. - [#2166](https://github.com/TokTok/c-toxcore/pull/2166) cleanup: Reduce scope of variables as requested by cimple. - [#2164](https://github.com/TokTok/c-toxcore/pull/2164) feat: Merge onion_announce changes from new groupchats fork - [#2163](https://github.com/TokTok/c-toxcore/pull/2163) chore: Enable memory sanitizer build. - [#2160](https://github.com/TokTok/c-toxcore/pull/2160) test: Improve the stability of the save_load test - [#2159](https://github.com/TokTok/c-toxcore/pull/2159) chore: Update the Appveyor build to VS2019 to work around conan issues - [#2158](https://github.com/TokTok/c-toxcore/pull/2158) cleanup: Expose `struct Tox` to internal code. - [#2157](https://github.com/TokTok/c-toxcore/pull/2157) cleanup: Split the huge TCP client packet handler. - [#2156](https://github.com/TokTok/c-toxcore/pull/2156) cleanup: Sync doc comments between .h and .c files. - [#2155](https://github.com/TokTok/c-toxcore/pull/2155) fix: Eliminate memory leak in toxav. - [#2154](https://github.com/TokTok/c-toxcore/pull/2154) test: Speed up toxav_many_test by using fake mono_time. - [#2153](https://github.com/TokTok/c-toxcore/pull/2153) docs: Put all the tox public api into a fake "tox" namespace. - [#2150](https://github.com/TokTok/c-toxcore/pull/2150) cleanup: Move all the group.h structs into group.c. - [#2149](https://github.com/TokTok/c-toxcore/pull/2149) cleanup: Avoid `memset` on structs. - [#2147](https://github.com/TokTok/c-toxcore/pull/2147) feat: Store announcements - [#2146](https://github.com/TokTok/c-toxcore/pull/2146) chore: Add testing/Dockerfile to the CI build. - [#2145](https://github.com/TokTok/c-toxcore/pull/2145) chore: Be even more explicit about integer range bounds. - [#2144](https://github.com/TokTok/c-toxcore/pull/2144) cleanup: Minor cleanups in TCP_connection.c. - [#2143](https://github.com/TokTok/c-toxcore/pull/2143) fix: Allow port range in DHT_bootstrap.c. - [#2142](https://github.com/TokTok/c-toxcore/pull/2142) cleanup: Count re-adding an existing bootstrap node as success. - [#2141](https://github.com/TokTok/c-toxcore/pull/2141) cleanup: Disable LAN discovery in TCP-only mode. - [#2140](https://github.com/TokTok/c-toxcore/pull/2140) cleanup: Add assertion for decrypted data length. - [#2101](https://github.com/TokTok/c-toxcore/pull/2101) cleanup: improve CMakeLists.txt structure - [#2100](https://github.com/TokTok/c-toxcore/pull/2100) chore: remove cpufeatures.c - [#2098](https://github.com/TokTok/c-toxcore/pull/2098) chore: remove DHT_test.c since it's unused ### Closed issues: - [#2298](https://github.com/TokTok/c-toxcore/issues/2298) assert makes incorrect assumption - [#2256](https://github.com/TokTok/c-toxcore/issues/2256) New Defects reported by Coverity Scan for TokTok/c-toxcore - [#2109](https://github.com/TokTok/c-toxcore/issues/2109) Assimilate `messenger_test.c`: replace with public API test - [#2012](https://github.com/TokTok/c-toxcore/issues/2012) Support building a DLL on Windows - [#907](https://github.com/TokTok/c-toxcore/issues/907) use dll abnormal System.AccessViolationException win7 x32 but x64 no problem ## v0.2.17 ### Merged PRs: - [#2138](https://github.com/TokTok/c-toxcore/pull/2138) chore: Release 0.2.17 - [#2136](https://github.com/TokTok/c-toxcore/pull/2136) docs: Clean up doxygen comments to be more doxygen-like. - [#2135](https://github.com/TokTok/c-toxcore/pull/2135) cleanup: Move test-only functions into tests. - [#2134](https://github.com/TokTok/c-toxcore/pull/2134) cleanup: Add explicit callback setters for MSI callbacks. - [#2133](https://github.com/TokTok/c-toxcore/pull/2133) cleanup: Remove redundant Messenger and DHT tests. - [#2132](https://github.com/TokTok/c-toxcore/pull/2132) cleanup: Remove dependency from LAN_discovery onto DHT. - [#2131](https://github.com/TokTok/c-toxcore/pull/2131) cleanup: Split util.c out of the network library. - [#2130](https://github.com/TokTok/c-toxcore/pull/2130) cleanup: Remove redundant `()` around `return` expression. - [#2128](https://github.com/TokTok/c-toxcore/pull/2128) test: Add unit test for create/handle request packets. - [#2127](https://github.com/TokTok/c-toxcore/pull/2127) cleanup: Remove `EAGAIN` from the list of ignored errors. - [#2126](https://github.com/TokTok/c-toxcore/pull/2126) cleanup: Remove port from `Broadcast_Info`. - [#2125](https://github.com/TokTok/c-toxcore/pull/2125) cleanup: Don't reference local variables in macro bodies. - [#2123](https://github.com/TokTok/c-toxcore/pull/2123) cleanup: Remove some more implicit bool conversions. - [#2122](https://github.com/TokTok/c-toxcore/pull/2122) chore: Enable a bunch more warnings in GCC builds. - [#2120](https://github.com/TokTok/c-toxcore/pull/2120) cleanup: Remove all boolean-int conversions. - [#2117](https://github.com/TokTok/c-toxcore/pull/2117) cleanup: Comply with strict include ordering. - [#2116](https://github.com/TokTok/c-toxcore/pull/2116) cleanup: Remove more boolean conversions (and a bugfix). - [#2115](https://github.com/TokTok/c-toxcore/pull/2115) cleanup: Log at ERROR level when `connect()` fails. - [#2114](https://github.com/TokTok/c-toxcore/pull/2114) cleanup: Avoid creating invalid enum values. - [#2113](https://github.com/TokTok/c-toxcore/pull/2113) cleanup: Remove superfluous parentheses on the rhs of assignments. - [#2108](https://github.com/TokTok/c-toxcore/pull/2108) test: Add mallocfail and proxy test to our coverage runs. - [#2106](https://github.com/TokTok/c-toxcore/pull/2106) test: Add test coverage docker build for local tests. - [#2105](https://github.com/TokTok/c-toxcore/pull/2105) cleanup: Change valid status of onion friend to bool. - [#2104](https://github.com/TokTok/c-toxcore/pull/2104) fix: Report failure to DHT bootstrap back to the client. - [#2103](https://github.com/TokTok/c-toxcore/pull/2103) cleanup: Remove more implicit bool conversions. - [#2102](https://github.com/TokTok/c-toxcore/pull/2102) cleanup: Mark all local non-pointers as const where possible. - [#2099](https://github.com/TokTok/c-toxcore/pull/2099) cleanup: Reduce name shadowing; remove ptr-to-bool conversions. - [#2097](https://github.com/TokTok/c-toxcore/pull/2097) cleanup: Remove implicit conversions from `uint32_t` to `bool`. - [#2096](https://github.com/TokTok/c-toxcore/pull/2096) cleanup: Return boolean constants, not ints from bool functions. - [#2094](https://github.com/TokTok/c-toxcore/pull/2094) fix: Null function pointer dereference. - [#2093](https://github.com/TokTok/c-toxcore/pull/2093) cleanup: Remove any disallowed casts. - [#2092](https://github.com/TokTok/c-toxcore/pull/2092) perf: fix issue with friend finding taking too long after disconnects. - [#2091](https://github.com/TokTok/c-toxcore/pull/2091) cleanup: Avoid casting function pointers. - [#2090](https://github.com/TokTok/c-toxcore/pull/2090) refactor: Move `tox_new_log` to `auto_test_support`. - [#2088](https://github.com/TokTok/c-toxcore/pull/2088) cleanup: Remove all implicit bool conversions in if-conditions. - [#2086](https://github.com/TokTok/c-toxcore/pull/2086) cleanup: Enable most cppcheck warnings as errors. - [#2084](https://github.com/TokTok/c-toxcore/pull/2084) fix: out-of-memory condition by corrupted save file - [#2079](https://github.com/TokTok/c-toxcore/pull/2079) cleanup: Remove unused execution trace library. - [#2078](https://github.com/TokTok/c-toxcore/pull/2078) perf: Refactor onion_client.c do_friends() to reduce network traffic - [#2075](https://github.com/TokTok/c-toxcore/pull/2075) chore: Add a .clang-format that mostly agrees with astyle. - [#2074](https://github.com/TokTok/c-toxcore/pull/2074) chore: Make coverity scan a nightly job. - [#2073](https://github.com/TokTok/c-toxcore/pull/2073) chore: Fix build-args in win32/win64 docker build. - [#2072](https://github.com/TokTok/c-toxcore/pull/2072) chore: Simplify and speed up windows builds using docker image. - [#2070](https://github.com/TokTok/c-toxcore/pull/2070) chore: Add docker image builds for windows cross compiler. - [#2064](https://github.com/TokTok/c-toxcore/pull/2064) fix: toxsave memory leak while loading groups ### Closed issues: - [#2121](https://github.com/TokTok/c-toxcore/issues/2121) Improve speed and stability of LAN discovery test - [#2083](https://github.com/TokTok/c-toxcore/issues/2083) Tox save file format/loader doesn't limit or check the number of frozen peers - [#2080](https://github.com/TokTok/c-toxcore/issues/2080) speedup getting online after tox process has been suspended - [#2050](https://github.com/TokTok/c-toxcore/issues/2050) Excessive onion friend lookups - [#2034](https://github.com/TokTok/c-toxcore/issues/2034) Make coverity-scan workflow a nightly build instead of on master push - [#2000](https://github.com/TokTok/c-toxcore/issues/2000) Move win32 docker image build out to dockerfiles - [#1990](https://github.com/TokTok/c-toxcore/issues/1990) Add a .clang-format config that matches the astyle config as closely as possible. - [#1115](https://github.com/TokTok/c-toxcore/issues/1115) Add empty handler for LAN discovery packets when LAN discovery is disabled - [#647](https://github.com/TokTok/c-toxcore/issues/647) `tox_bootstrap` should return an error on unrecoverable `getnodes` failure - [#169](https://github.com/TokTok/c-toxcore/issues/169) Get rid of TOX_USER_STATUS_BUSY + 1 ## v0.2.16 ### Merged PRs: - [#2071](https://github.com/TokTok/c-toxcore/pull/2071) chore: Release 0.2.16 - [#2069](https://github.com/TokTok/c-toxcore/pull/2069) chore: Simplify and speed up nacl build using toxchat/nacl. - [#2066](https://github.com/TokTok/c-toxcore/pull/2066) test: Add a profiling script and Dockerfile. - [#2058](https://github.com/TokTok/c-toxcore/pull/2058) fix: properly deallocate frozen peers - [#2056](https://github.com/TokTok/c-toxcore/pull/2056) cleanup: Avoid implicit boolean and floating point conversions in decls. - [#2055](https://github.com/TokTok/c-toxcore/pull/2055) cleanup: Avoid implicit bool conversions in logical operators. - [#2053](https://github.com/TokTok/c-toxcore/pull/2053) cleanup: Enable tokstyle's `-Wlarge-struct-params`. - [#2052](https://github.com/TokTok/c-toxcore/pull/2052) fix: Fix return type of functions returning uint64_t. - [#2049](https://github.com/TokTok/c-toxcore/pull/2049) cleanup: Apply stronger type checks and fix errors. - [#2047](https://github.com/TokTok/c-toxcore/pull/2047) feat: Improve how we share TCP relays with friends - [#2046](https://github.com/TokTok/c-toxcore/pull/2046) cleanup: Avoid implicit pointer-to-bool conversion in `if` in toxav. - [#2043](https://github.com/TokTok/c-toxcore/pull/2043) refactor: Compare pointers in if conditions to nullptr. - [#2041](https://github.com/TokTok/c-toxcore/pull/2041) fix: file transfer bug introduced in commit 2073d02 - [#2039](https://github.com/TokTok/c-toxcore/pull/2039) refactor: Add a bit more logging; change WARNING to ERROR. - [#2036](https://github.com/TokTok/c-toxcore/pull/2036) chore: Add BUILD file for websockify. - [#2035](https://github.com/TokTok/c-toxcore/pull/2035) chore: fine tune fuzzing settings - [#2033](https://github.com/TokTok/c-toxcore/pull/2033) cleanup: Add some more error path logging to TCP server code. - [#2032](https://github.com/TokTok/c-toxcore/pull/2032) chore: update the list of CMake options & Windows Docker build deps - [#2031](https://github.com/TokTok/c-toxcore/pull/2031) fix: remove bogus asserts in fuzzer harness - [#2030](https://github.com/TokTok/c-toxcore/pull/2030) chore: expand fuzzing to toxsave - [#2028](https://github.com/TokTok/c-toxcore/pull/2028) fix: syntax error introduced in 8bf37994fd12acec9e3010437502f478399b99b4 - [#2027](https://github.com/TokTok/c-toxcore/pull/2027) fix: add continous fuzzing - [#2026](https://github.com/TokTok/c-toxcore/pull/2026) chore: Fix implicit declaration warning in fuzz build - [#2025](https://github.com/TokTok/c-toxcore/pull/2025) chore: add continous fuzzing to our CI - [#2024](https://github.com/TokTok/c-toxcore/pull/2024) perf: Reduce minimal encoding size of packed events. - [#2023](https://github.com/TokTok/c-toxcore/pull/2023) cleanup: Add wrapper library for msgpack pack functions - [#2022](https://github.com/TokTok/c-toxcore/pull/2022) cleanup: Split tox_unpack into two smaller libs - [#2021](https://github.com/TokTok/c-toxcore/pull/2021) chore: Disable non-null attributes by default. - [#2019](https://github.com/TokTok/c-toxcore/pull/2019) chore: Silence clang compile warnings causing circle-ci/asan to fail - [#2018](https://github.com/TokTok/c-toxcore/pull/2018) fix: Coverty scan - [#2016](https://github.com/TokTok/c-toxcore/pull/2016) docs: Add libmsgpack dependency in INSTALL.md - [#2015](https://github.com/TokTok/c-toxcore/pull/2015) fix: shared toxcore autotools build failing - [#2013](https://github.com/TokTok/c-toxcore/pull/2013) cleanup: Don't use VLAs for huge allocations. - [#2011](https://github.com/TokTok/c-toxcore/pull/2011) fix: Conan build link failures - [#2010](https://github.com/TokTok/c-toxcore/pull/2010) chore: Remove duplicate source file in autotools build. - [#2008](https://github.com/TokTok/c-toxcore/pull/2008) chore: get skeletons out of the closet - [#2007](https://github.com/TokTok/c-toxcore/pull/2007) feat: add bash-completion for tox-bootstrapd - [#2006](https://github.com/TokTok/c-toxcore/pull/2006) cleanup: Add more nonnull and nullable annotations. - [#2002](https://github.com/TokTok/c-toxcore/pull/2002) cleanup: Add nonnull annotations to function definitions. - [#2001](https://github.com/TokTok/c-toxcore/pull/2001) chore: Add an undefined behaviour/integer sanitizer build. - [#1999](https://github.com/TokTok/c-toxcore/pull/1999) chore: Speed up cmake builds with `UNITY_BUILD`. - [#1996](https://github.com/TokTok/c-toxcore/pull/1996) feat: Add unpacker functions for events structures. - [#1993](https://github.com/TokTok/c-toxcore/pull/1993) feat: Add binary packing functions for tox events. - [#1992](https://github.com/TokTok/c-toxcore/pull/1992) chore: Set up an Android CI job - [#1988](https://github.com/TokTok/c-toxcore/pull/1988) cleanup: Make LAN discovery thread-safe without data races. - [#1987](https://github.com/TokTok/c-toxcore/pull/1987) cleanup: Comply with new cimple callback rules. - [#1985](https://github.com/TokTok/c-toxcore/pull/1985) cleanup: Split msi callback array into 1 member per callback - [#1982](https://github.com/TokTok/c-toxcore/pull/1982) chore: Add an easy way to run autotools and circleci builds locally. - [#1979](https://github.com/TokTok/c-toxcore/pull/1979) chore: Update readme header - [#1952](https://github.com/TokTok/c-toxcore/pull/1952) feat: Add async event handling (callbacks) code. - [#1935](https://github.com/TokTok/c-toxcore/pull/1935) feat: add DHT queries to private API - [#1668](https://github.com/TokTok/c-toxcore/pull/1668) perf: Take advantage of fast networks for file transfers ### Closed issues: - [#2009](https://github.com/TokTok/c-toxcore/issues/2009) Autotools build fails - [#2004](https://github.com/TokTok/c-toxcore/issues/2004) Add `nullable` and `nonnull` annotations to all functions. - [#1998](https://github.com/TokTok/c-toxcore/issues/1998) Large stack allocations - [#1977](https://github.com/TokTok/c-toxcore/issues/1977) Turn array of callbacks in msi.h into separate callbacks. - [#1670](https://github.com/TokTok/c-toxcore/issues/1670) Broken link in readme - [#405](https://github.com/TokTok/c-toxcore/issues/405) Remove all¹ uses of global state in toxcore - [#340](https://github.com/TokTok/c-toxcore/issues/340) Set up a continuous integration build for Android - [#236](https://github.com/TokTok/c-toxcore/issues/236) Tox file transfers do not use available bandwidth - [#128](https://github.com/TokTok/c-toxcore/issues/128) Toxcore should provide an easy, local method for making sure Travis checks will pass ## v0.2.15 ### Merged PRs: - [#1984](https://github.com/TokTok/c-toxcore/pull/1984) fix: Reduce logging verbosity even more. - [#1983](https://github.com/TokTok/c-toxcore/pull/1983) chore: Release 0.2.15 - [#1980](https://github.com/TokTok/c-toxcore/pull/1980) fix: Reduce logging verbosity in TCP server. ## v0.2.14 ### Merged PRs: - [#1978](https://github.com/TokTok/c-toxcore/pull/1978) chore: Release 0.2.14 - [#1976](https://github.com/TokTok/c-toxcore/pull/1976) docs: Make crypto_core.h appear on doxygen. - [#1975](https://github.com/TokTok/c-toxcore/pull/1975) refactor: use proper method for generating random numbers in a range - [#1974](https://github.com/TokTok/c-toxcore/pull/1974) docs: Add doxygen configuration and netlify publishing. - [#1972](https://github.com/TokTok/c-toxcore/pull/1972) chore: Make the last few remaining top level comments doxygen style. - [#1971](https://github.com/TokTok/c-toxcore/pull/1971) chore: Sync all comments between header and source files. - [#1968](https://github.com/TokTok/c-toxcore/pull/1968) cleanup: Ensure we limit the system headers included in .h files. - [#1964](https://github.com/TokTok/c-toxcore/pull/1964) cleanup: Don't pass the whole DHT object to lan discovery. - [#1958](https://github.com/TokTok/c-toxcore/pull/1958) chore: Make run-infer script use docker. - [#1956](https://github.com/TokTok/c-toxcore/pull/1956) chore: Disable some cimple warnings for now. - [#1955](https://github.com/TokTok/c-toxcore/pull/1955) cleanup: Properly copy Node_format using serialized format - [#1954](https://github.com/TokTok/c-toxcore/pull/1954) cleanup: make functions take const pointer to IP_Port wherever possible - [#1950](https://github.com/TokTok/c-toxcore/pull/1950) feat: Add WASM build for toxcore and websocket bootstrap node. - [#1948](https://github.com/TokTok/c-toxcore/pull/1948) fix: potential freeing of an immutable static buffer - [#1945](https://github.com/TokTok/c-toxcore/pull/1945) fix: Fix bootstrap on emscripten/wasm. - [#1943](https://github.com/TokTok/c-toxcore/pull/1943) chore: use latest toktok-stack msan version - [#1942](https://github.com/TokTok/c-toxcore/pull/1942) cleanup: Add some toxav bounds/sanity checks - [#1940](https://github.com/TokTok/c-toxcore/pull/1940) chore: Use latest instead of versioned toktok-stack image. - [#1939](https://github.com/TokTok/c-toxcore/pull/1939) chore: Rename bazel-release to -opt and -debug to -dbg. - [#1938](https://github.com/TokTok/c-toxcore/pull/1938) cleanup: small refactor of DHT getnodes function - [#1937](https://github.com/TokTok/c-toxcore/pull/1937) cleanup: remove brackets from ip_ntoa ipv6 formatting - [#1933](https://github.com/TokTok/c-toxcore/pull/1933) chore: Add a Bazel Buildifier CI job - [#1932](https://github.com/TokTok/c-toxcore/pull/1932) test: separate run_auto_tests into a library (revival of #1505) - [#1929](https://github.com/TokTok/c-toxcore/pull/1929) cleanup: make some non-const pointers const - [#1928](https://github.com/TokTok/c-toxcore/pull/1928) fix: unintentional integer down-casts - [#1926](https://github.com/TokTok/c-toxcore/pull/1926) fix: group av memory leak - [#1924](https://github.com/TokTok/c-toxcore/pull/1924) test: refactor autotest live network bootstrapping - [#1923](https://github.com/TokTok/c-toxcore/pull/1923) fix: corruption in key files, making it unable to load when node starts. - [#1922](https://github.com/TokTok/c-toxcore/pull/1922) chore: Don't run sonar scan on pull requests. - [#1920](https://github.com/TokTok/c-toxcore/pull/1920) cleanup: refactor group audio packet data handling - [#1918](https://github.com/TokTok/c-toxcore/pull/1918) chore: Run sonar scan on pull requests. - [#1917](https://github.com/TokTok/c-toxcore/pull/1917) fix: buffer overwrite in bootstrap config - [#1916](https://github.com/TokTok/c-toxcore/pull/1916) chore: Add a make_single_file script, used for CI. - [#1915](https://github.com/TokTok/c-toxcore/pull/1915) cleanup: replace magic numbers with appropriately named constants - [#1914](https://github.com/TokTok/c-toxcore/pull/1914) chore: Add cpplint to the CI. - [#1912](https://github.com/TokTok/c-toxcore/pull/1912) cleanup: Remove uses of `strcpy` and `sprintf`. - [#1910](https://github.com/TokTok/c-toxcore/pull/1910) cleanup: Remove our only use of flexible array members in toxcore. - [#1909](https://github.com/TokTok/c-toxcore/pull/1909) chore: Expose public API headers as files in bazel. - [#1906](https://github.com/TokTok/c-toxcore/pull/1906) cleanup: Split large switch statement into functions. - [#1905](https://github.com/TokTok/c-toxcore/pull/1905) chore: Mark unsafe code as testonly. - [#1903](https://github.com/TokTok/c-toxcore/pull/1903) cleanup: Even more pointer-to-const parameters. - [#1901](https://github.com/TokTok/c-toxcore/pull/1901) cleanup: Make parameters pointers-to-const where possible. - [#1900](https://github.com/TokTok/c-toxcore/pull/1900) cleanup: Remove old check Suite compat layer. - [#1899](https://github.com/TokTok/c-toxcore/pull/1899) cleanup: Make `Networking_Core` pointer-to-const where possible. - [#1898](https://github.com/TokTok/c-toxcore/pull/1898) cleanup: Use pointer cast instead of memcpy in qsort callback. - [#1897](https://github.com/TokTok/c-toxcore/pull/1897) refactor: Deduplicate a bunch of code in TCP client/server. - [#1894](https://github.com/TokTok/c-toxcore/pull/1894) cleanup: Deduplicate a somewhat complex loop in DHT.c. - [#1891](https://github.com/TokTok/c-toxcore/pull/1891) cleanup: Remove our only use of sprintf. - [#1889](https://github.com/TokTok/c-toxcore/pull/1889) cleanup: Stop using `strerror` directly. - [#1887](https://github.com/TokTok/c-toxcore/pull/1887) test: Add two more bootstrap/TCP nodes to autotests - [#1884](https://github.com/TokTok/c-toxcore/pull/1884) chore: Add mypy Python type check. - [#1883](https://github.com/TokTok/c-toxcore/pull/1883) chore: Add sonar-scan analysis on pushes. - [#1881](https://github.com/TokTok/c-toxcore/pull/1881) cleanup: Merge crypto_core and crypto_core_mem. - [#1880](https://github.com/TokTok/c-toxcore/pull/1880) chore: Run static analysers in multiple variants. - [#1879](https://github.com/TokTok/c-toxcore/pull/1879) fix: Fix `toxav_basic_test` buffer overflow. - [#1878](https://github.com/TokTok/c-toxcore/pull/1878) fix: don't count filetransfer as sending until accepted - [#1877](https://github.com/TokTok/c-toxcore/pull/1877) fix: Fix some uninitialised memory errors found by valgrind. - [#1876](https://github.com/TokTok/c-toxcore/pull/1876) chore: Ignore some failures in bazel-tsan. - [#1875](https://github.com/TokTok/c-toxcore/pull/1875) chore: Add asan/tsan bazel builds. - [#1874](https://github.com/TokTok/c-toxcore/pull/1874) cleanup: replace all instances of atoi with strtol - [#1873](https://github.com/TokTok/c-toxcore/pull/1873) chore: Enable layering check in all c-toxcore build files. - [#1871](https://github.com/TokTok/c-toxcore/pull/1871) chore: Enable compiler layering check. - [#1870](https://github.com/TokTok/c-toxcore/pull/1870) chore: Disable the OpenMP cracker in bazel for now. - [#1867](https://github.com/TokTok/c-toxcore/pull/1867) chore: Retry asan/tsan tests a few more times. - [#1866](https://github.com/TokTok/c-toxcore/pull/1866) chore: Run tokstyle with 3 cores. - [#1865](https://github.com/TokTok/c-toxcore/pull/1865) cleanup: Remove extra parens around function arguments. - [#1864](https://github.com/TokTok/c-toxcore/pull/1864) cleanup: Don't use memcpy where assignment can be used. - [#1862](https://github.com/TokTok/c-toxcore/pull/1862) chore: Remove all references to Travis CI. - [#1861](https://github.com/TokTok/c-toxcore/pull/1861) cleanup: Use `calloc` instead of `malloc` for struct allocations. - [#1860](https://github.com/TokTok/c-toxcore/pull/1860) cleanup: Fix `calloc` argument order. - [#1857](https://github.com/TokTok/c-toxcore/pull/1857) chore: Get all* autotests working with MSVC - [#1853](https://github.com/TokTok/c-toxcore/pull/1853) cleanup: Remove useless parentheses. - [#1850](https://github.com/TokTok/c-toxcore/pull/1850) chore: Add a GH Actions code coverage job - [#1845](https://github.com/TokTok/c-toxcore/pull/1845) fix: use correct sample size in toxav_basic_test - [#1844](https://github.com/TokTok/c-toxcore/pull/1844) cleanup: make struct typedefs have the same name as their struct - [#1841](https://github.com/TokTok/c-toxcore/pull/1841) cleanup: refactor toxav_call_control - [#1840](https://github.com/TokTok/c-toxcore/pull/1840) chore: Remove old travis docker scripts. - [#1837](https://github.com/TokTok/c-toxcore/pull/1837) chore: Add bazel-debug build. - [#1836](https://github.com/TokTok/c-toxcore/pull/1836) fix: possible unintended negative loop bound - [#1835](https://github.com/TokTok/c-toxcore/pull/1835) cleanup: remove dead code - [#1834](https://github.com/TokTok/c-toxcore/pull/1834) cleanup: Reduce the scope of for-loop iterator variables. - [#1832](https://github.com/TokTok/c-toxcore/pull/1832) fix: a double-unlocking mutex in toxav - [#1830](https://github.com/TokTok/c-toxcore/pull/1830) chore: Add "tcc" and "compcert" compiler targets. - [#1820](https://github.com/TokTok/c-toxcore/pull/1820) chore: Add macOS build. - [#1819](https://github.com/TokTok/c-toxcore/pull/1819) refactor: Extract some functions from the big run_auto_test function. - [#1818](https://github.com/TokTok/c-toxcore/pull/1818) feat: Add programs for creating savedata & bootstrap keys - [#1816](https://github.com/TokTok/c-toxcore/pull/1816) cleanup: put breaks inside case braces - [#1815](https://github.com/TokTok/c-toxcore/pull/1815) test: add ability for autotests to use TCP connections - [#1813](https://github.com/TokTok/c-toxcore/pull/1813) chore: Login to dockerhub before trying to push to dockerhub. - [#1812](https://github.com/TokTok/c-toxcore/pull/1812) chore: Only push versioned docker image on tag builds. - [#1811](https://github.com/TokTok/c-toxcore/pull/1811) chore: Add bootstrap daemon docker image build. - [#1810](https://github.com/TokTok/c-toxcore/pull/1810) chore: Remove apidsl comment from tox.h. - [#1807](https://github.com/TokTok/c-toxcore/pull/1807) chore: Don't run CI on master branch pushes. - [#1802](https://github.com/TokTok/c-toxcore/pull/1802) cleanup: Sync doc comments in a few more .c/.h files. - [#1801](https://github.com/TokTok/c-toxcore/pull/1801) chore: Fix up a few source code comment and style issues. - [#1798](https://github.com/TokTok/c-toxcore/pull/1798) chore: merge friend_connections from NGC fork - [#1797](https://github.com/TokTok/c-toxcore/pull/1797) cleanup: Move `sodium.h` include to front of network.c. - [#1794](https://github.com/TokTok/c-toxcore/pull/1794) chore: Move cmake-freebsd-stage2 back into the toxcore repo. - [#1793](https://github.com/TokTok/c-toxcore/pull/1793) chore: Add FreeBSD build to CI. - [#1792](https://github.com/TokTok/c-toxcore/pull/1792) chore: Add cross compilation CI targets. - [#1790](https://github.com/TokTok/c-toxcore/pull/1790) cleanup: remove redundant (and incorrect) comments - [#1789](https://github.com/TokTok/c-toxcore/pull/1789) refactor: rename variable to clarify purpose - [#1786](https://github.com/TokTok/c-toxcore/pull/1786) cleanup: Remove apidsl; remove `crypto_memcmp`. - [#1783](https://github.com/TokTok/c-toxcore/pull/1783) cleanup: fix format-source - [#1779](https://github.com/TokTok/c-toxcore/pull/1779) chore: Update toktok-stack version. - [#1778](https://github.com/TokTok/c-toxcore/pull/1778) chore: Tie down the use of doxygen comments. - [#1777](https://github.com/TokTok/c-toxcore/pull/1777) cleanup: Remove crypto_pwhash import. - [#1776](https://github.com/TokTok/c-toxcore/pull/1776) cleanup: remove unused function argument from set_tcp_connection_status() - [#1775](https://github.com/TokTok/c-toxcore/pull/1775) cleanup: Remove apidsl for everything except the public API. - [#1774](https://github.com/TokTok/c-toxcore/pull/1774) chore: Remove config.h. - [#1773](https://github.com/TokTok/c-toxcore/pull/1773) chore: Fix gen-file.sh: it wasn't globbing properly. - [#1772](https://github.com/TokTok/c-toxcore/pull/1772) chore: Add .cc files to the static analysis. - [#1770](https://github.com/TokTok/c-toxcore/pull/1770) cleanup: merge onion.c changes from new groupchats fork - [#1769](https://github.com/TokTok/c-toxcore/pull/1769) chore: merge tcp_connection changes from new groupchats fork - [#1768](https://github.com/TokTok/c-toxcore/pull/1768) chore: merge DHT changes from new groupchats fork - [#1766](https://github.com/TokTok/c-toxcore/pull/1766) chore: Use docker for the autotools ci build. - [#1765](https://github.com/TokTok/c-toxcore/pull/1765) fix: Fix file permission issue with toxchat/bootstrap-node Docker container - [#1762](https://github.com/TokTok/c-toxcore/pull/1762) chore: Add autotools build; exempt crypto_pwhash from tokstyle. - [#1761](https://github.com/TokTok/c-toxcore/pull/1761) cleanup: Don't include `"config.h"` unless needed. - [#1759](https://github.com/TokTok/c-toxcore/pull/1759) cleanup: address some unused return values - [#1758](https://github.com/TokTok/c-toxcore/pull/1758) test: Make ERROR logging fatal in tests. - [#1754](https://github.com/TokTok/c-toxcore/pull/1754) fix: off-by-one error caused by integer division without proper cast - [#1753](https://github.com/TokTok/c-toxcore/pull/1753) cleanup: use crypto_memzero to wipe secret keys when no longer in use - [#1752](https://github.com/TokTok/c-toxcore/pull/1752) chore: Use an incrementing version number for coverity scans. - [#1751](https://github.com/TokTok/c-toxcore/pull/1751) fix: Fixed uninitialised value copy. - [#1747](https://github.com/TokTok/c-toxcore/pull/1747) cleanup: Fix some clang-tidy warnings and make them errors. - [#1746](https://github.com/TokTok/c-toxcore/pull/1746) chore: Add clang-tidy review github workflow. - [#1744](https://github.com/TokTok/c-toxcore/pull/1744) cleanup: Enforce for loop consistency. - [#1743](https://github.com/TokTok/c-toxcore/pull/1743) chore: Minor cleanups of warnings given by cppcheck. - [#1742](https://github.com/TokTok/c-toxcore/pull/1742) test: Add a simple test for `ip_ntoa`. - [#1740](https://github.com/TokTok/c-toxcore/pull/1740) cleanup: Put fatal errors where API return values should be impossible - [#1738](https://github.com/TokTok/c-toxcore/pull/1738) chore: Add missing `sudo` to coverity apt-get calls. - [#1737](https://github.com/TokTok/c-toxcore/pull/1737) refactor: Fix previous refactor - [#1736](https://github.com/TokTok/c-toxcore/pull/1736) chore: Add workflow for running coverity scan. - [#1735](https://github.com/TokTok/c-toxcore/pull/1735) cleanup: Use `static_assert` instead of preprocessor `#error`. - [#1734](https://github.com/TokTok/c-toxcore/pull/1734) chore: Add logger to onion and onion announce objects - [#1733](https://github.com/TokTok/c-toxcore/pull/1733) cleanup: Minor fixes in test code. - [#1732](https://github.com/TokTok/c-toxcore/pull/1732) cleanup: Refactor kill_nonused_tcp() - [#1730](https://github.com/TokTok/c-toxcore/pull/1730) cleanup: Fix last instance of `-Wcast-align` and enable the warning. - [#1729](https://github.com/TokTok/c-toxcore/pull/1729) cleanup: Ensure that error codes are always initialised. - [#1727](https://github.com/TokTok/c-toxcore/pull/1727) cleanup: Avoid endian-specific code in `crypto_core`. - [#1720](https://github.com/TokTok/c-toxcore/pull/1720) feat: Add automatic fuzz testing for c-toxcore - [#1673](https://github.com/TokTok/c-toxcore/pull/1673) cleanup: Remove hardening code from DHT - [#1622](https://github.com/TokTok/c-toxcore/pull/1622) perf: Make the key cracker a bit faster - [#1333](https://github.com/TokTok/c-toxcore/pull/1333) refactor: Clean up friend loading. - [#1307](https://github.com/TokTok/c-toxcore/pull/1307) refactor: Split toxav_iterate into audio and video part ### Closed issues: - [#1967](https://github.com/TokTok/c-toxcore/issues/1967) Potential freeing of an immutable static buffer - [#1788](https://github.com/TokTok/c-toxcore/issues/1788) Rename dht->last_run - [#1719](https://github.com/TokTok/c-toxcore/issues/1719) Enforce braces around macros that compute a value - [#1694](https://github.com/TokTok/c-toxcore/issues/1694) Double unlocking in the ac_iterate - [#1332](https://github.com/TokTok/c-toxcore/issues/1332) Padding bytes in Tox save format are not specified - [#1217](https://github.com/TokTok/c-toxcore/issues/1217) valgrind reports "Conditional jump or move depends on uninitialised value(s)" - [#1118](https://github.com/TokTok/c-toxcore/issues/1118) Fix threading issues in tests caught by tsan (data race etc) - [#1087](https://github.com/TokTok/c-toxcore/issues/1087) Remove all uses of `%zu` in printf formats. - [#1040](https://github.com/TokTok/c-toxcore/issues/1040) Random numbers should not be produced using `rng() % max`. - [#540](https://github.com/TokTok/c-toxcore/issues/540) Stop deleting source files - [#501](https://github.com/TokTok/c-toxcore/issues/501) Testsuite fails and hangs on FreeBSD - [#451](https://github.com/TokTok/c-toxcore/issues/451) Don't fail when building toxcore on windows with `cmake .` - [#350](https://github.com/TokTok/c-toxcore/issues/350) Configure coverity runs for nightly builds - [#349](https://github.com/TokTok/c-toxcore/issues/349) Run clang-tidy on Travis with specific warnings as errors. - [#348](https://github.com/TokTok/c-toxcore/issues/348) Run cppcheck on Travis and push the results to toktok.github.io. - [#323](https://github.com/TokTok/c-toxcore/issues/323) Set library version on future releases - [#235](https://github.com/TokTok/c-toxcore/issues/235) Video corruption: Don't drop video keyframes - [#203](https://github.com/TokTok/c-toxcore/issues/203) ToxAV is still on the old API style - [#198](https://github.com/TokTok/c-toxcore/issues/198) Crash on call while peer calling you - [#167](https://github.com/TokTok/c-toxcore/issues/167) Const-ify pointers - [#124](https://github.com/TokTok/c-toxcore/issues/124) Don't include OS specific headers in .h files - [#106](https://github.com/TokTok/c-toxcore/issues/106) Sometimes Toxcore reports the wrong connection status for both the DHT, and friends. - [#85](https://github.com/TokTok/c-toxcore/issues/85) Reproducible Builds // OBS a bad Idea ## v0.2.13 ### Merged PRs: - [#1725](https://github.com/TokTok/c-toxcore/pull/1725) cleanup: add some missing null checks - [#1723](https://github.com/TokTok/c-toxcore/pull/1723) chore: Run infer static analyser on circle ci builds. - [#1722](https://github.com/TokTok/c-toxcore/pull/1722) chore: Release 0.2.13 - [#1718](https://github.com/TokTok/c-toxcore/pull/1718) fix: Sec/fix crypto size compute - [#1716](https://github.com/TokTok/c-toxcore/pull/1716) chore: Use toktok-stack docker image with built third_party. - [#1713](https://github.com/TokTok/c-toxcore/pull/1713) test: Add some unit tests for important internal DHT functions. - [#1708](https://github.com/TokTok/c-toxcore/pull/1708) perf: reduce calling into Mono_Time in DHT - [#1706](https://github.com/TokTok/c-toxcore/pull/1706) chore: Enable cimple tests on cirrus build. - [#1705](https://github.com/TokTok/c-toxcore/pull/1705) fix: issue with save_load autotest - [#1703](https://github.com/TokTok/c-toxcore/pull/1703) chore: Upgrade to toktok-stack:0.0.11. - [#1699](https://github.com/TokTok/c-toxcore/pull/1699) fix: some friend connection issues - [#1698](https://github.com/TokTok/c-toxcore/pull/1698) fix: bug causing API to report wrong self connection status - [#1693](https://github.com/TokTok/c-toxcore/pull/1693) chore: Update IRC info - [#1691](https://github.com/TokTok/c-toxcore/pull/1691) chore: Fix Appveyor and add workarounds for Cirrus CI - [#1686](https://github.com/TokTok/c-toxcore/pull/1686) chore: Enable c-toxcore conan packaging - [#1684](https://github.com/TokTok/c-toxcore/pull/1684) cleanup: Update INSTALL.md instructions - [#1679](https://github.com/TokTok/c-toxcore/pull/1679) cleanup: Trivial cleanup - [#1674](https://github.com/TokTok/c-toxcore/pull/1674) cleanup: filetransfer code - [#1672](https://github.com/TokTok/c-toxcore/pull/1672) docs: Add instructions for building unit tests to INSTALL.md - [#1667](https://github.com/TokTok/c-toxcore/pull/1667) chore: Update tox-bootstrapd checksum due to newer packages in Alpine - [#1664](https://github.com/TokTok/c-toxcore/pull/1664) cleanup: use heap memory instead of stack for large variables - [#1663](https://github.com/TokTok/c-toxcore/pull/1663) fix: Fix file tests on windows - [#1633](https://github.com/TokTok/c-toxcore/pull/1633) fix: AppVeyor failing due to conan remote being added twice - [#1602](https://github.com/TokTok/c-toxcore/pull/1602) fix: Fix buffer over-read when a peer leaves a conference - [#1586](https://github.com/TokTok/c-toxcore/pull/1586) test: Fix tcp_relay_test by adding a second bootstrap node. - [#1580](https://github.com/TokTok/c-toxcore/pull/1580) style: Format comments according to tokstyle's requirements. - [#1557](https://github.com/TokTok/c-toxcore/pull/1557) chore: Add conan support - [#1537](https://github.com/TokTok/c-toxcore/pull/1537) chore: Cygwin build - [#1516](https://github.com/TokTok/c-toxcore/pull/1516) cleanup: Make pylint and mypy happy with bootstrap_node_info.py. - [#1515](https://github.com/TokTok/c-toxcore/pull/1515) style: Run restyled on Travis and Circle CI scripts. - [#1514](https://github.com/TokTok/c-toxcore/pull/1514) refactor: Remove multi-declarators entirely. - [#1513](https://github.com/TokTok/c-toxcore/pull/1513) refactor: Disallow multiple initialised declarators per decl. - [#1510](https://github.com/TokTok/c-toxcore/pull/1510) chore: Don't build pushes to branches, only to tags. - [#1504](https://github.com/TokTok/c-toxcore/pull/1504) chore: Remove release-drafter configuration in favour of global one. - [#1498](https://github.com/TokTok/c-toxcore/pull/1498) refactor: Limit scope of loop iterators. - [#1497](https://github.com/TokTok/c-toxcore/pull/1497) refactor: Use bash arrays instead of strings for static analysis scripts. - [#1496](https://github.com/TokTok/c-toxcore/pull/1496) cleanup: Stop hard-coding packet IDs in tests. - [#1495](https://github.com/TokTok/c-toxcore/pull/1495) chore: Exclude imported libsodium sources from restyled. - [#1493](https://github.com/TokTok/c-toxcore/pull/1493) feat: Add logging to TCP and onion client. - [#1489](https://github.com/TokTok/c-toxcore/pull/1489) cleanup: `NAC_LIBS` -> `NACL_LIBS`. - [#1487](https://github.com/TokTok/c-toxcore/pull/1487) chore: Add autotools build to localbuild docker images. - [#1473](https://github.com/TokTok/c-toxcore/pull/1473) chore: Add a script to run Travis CI locally. - [#1467](https://github.com/TokTok/c-toxcore/pull/1467) fix: Fix a bug in savedata loading when malloc fails. - [#1464](https://github.com/TokTok/c-toxcore/pull/1464) fix: Fix errors on error paths found by oomer. - [#1463](https://github.com/TokTok/c-toxcore/pull/1463) cleanup: Add a check that we don't have any unused functions. - [#1462](https://github.com/TokTok/c-toxcore/pull/1462) cleanup: Include `` for `explicit_bzero`. - [#1436](https://github.com/TokTok/c-toxcore/pull/1436) chore: Enable cimple tests by default but allow disabling them. ### Closed issues: - [#1598](https://github.com/TokTok/c-toxcore/issues/1598) ERROR: heap-buffer-overflow in group.c found with AddressSanitizer - [#1326](https://github.com/TokTok/c-toxcore/issues/1326) the cause is great, but this thing is completely unusable - [#1319](https://github.com/TokTok/c-toxcore/issues/1319) Is this new application is safe & trusted ?? - [#1236](https://github.com/TokTok/c-toxcore/issues/1236) Ruby Extension? - [#1149](https://github.com/TokTok/c-toxcore/issues/1149) uTox aborts on toxcore restart - [#886](https://github.com/TokTok/c-toxcore/issues/886) Maybe need to set the stacksize for musl-libc ## v0.2.12 ### Merged PRs: - [#1458](https://github.com/TokTok/c-toxcore/pull/1458) Release 0.2.12 - [#1457](https://github.com/TokTok/c-toxcore/pull/1457) Disable non-hermetic tests by default. - [#1456](https://github.com/TokTok/c-toxcore/pull/1456) Limit the number of friends you can have to ~4 billion. - [#1452](https://github.com/TokTok/c-toxcore/pull/1452) Add execution trace option for debugging. - [#1444](https://github.com/TokTok/c-toxcore/pull/1444) Set up release-drafter to automatically draft the next release. - [#1443](https://github.com/TokTok/c-toxcore/pull/1443) Allow test coverage to fluctuate 2% up and down, but not below 80%. - [#1442](https://github.com/TokTok/c-toxcore/pull/1442) Add CODEOWNERS and settings.yml files. - [#1441](https://github.com/TokTok/c-toxcore/pull/1441) [ImgBot] Optimize images - [#1439](https://github.com/TokTok/c-toxcore/pull/1439) Fix continuous integration builds. - [#1437](https://github.com/TokTok/c-toxcore/pull/1437) Rework the toxchat/bootstrap-node Docker image. - [#1435](https://github.com/TokTok/c-toxcore/pull/1435) Enable TCP relay test in Bazel and autotools build. - [#1434](https://github.com/TokTok/c-toxcore/pull/1434) Skip invalid TCP relays and DHT nodes when loading save data. - [#1433](https://github.com/TokTok/c-toxcore/pull/1433) Fix saving of combination of loaded and connected TCP relays - [#1430](https://github.com/TokTok/c-toxcore/pull/1430) Invert `not_valid` functions and name them `is_valid`. - [#1429](https://github.com/TokTok/c-toxcore/pull/1429) Fix things not being initialized if creating a TCP-only network - [#1426](https://github.com/TokTok/c-toxcore/pull/1426) Remove tokstyle exemptions from build files. - [#1425](https://github.com/TokTok/c-toxcore/pull/1425) Stop using the "inline namespace" feature of apidsl. - [#1424](https://github.com/TokTok/c-toxcore/pull/1424) Add new semi-private API functions to set per-packet-id custom handlers. - [#1423](https://github.com/TokTok/c-toxcore/pull/1423) Give CI workflow a better name: clang-sanitizers - [#1422](https://github.com/TokTok/c-toxcore/pull/1422) Use public API for sending in RTP - [#1421](https://github.com/TokTok/c-toxcore/pull/1421) Install ci-tools and get tokstyle via the script it provides. - [#1420](https://github.com/TokTok/c-toxcore/pull/1420) Use tox public API for sending packets in toxav BWController - [#1419](https://github.com/TokTok/c-toxcore/pull/1419) Remove newlines from the end of LOGGER format strings. - [#1418](https://github.com/TokTok/c-toxcore/pull/1418) Change ToxAVCall struct mutex to a more distinct name - [#1417](https://github.com/TokTok/c-toxcore/pull/1417) Create own instance of Mono_Time for ToxAV - [#1416](https://github.com/TokTok/c-toxcore/pull/1416) Stop using Messenger's mono_time in bandwidth controller. - [#1415](https://github.com/TokTok/c-toxcore/pull/1415) Fix 2 memory leaks in ToxAV. - [#1414](https://github.com/TokTok/c-toxcore/pull/1414) Show function names in asan/tsan stack traces on CircleCI. - [#1413](https://github.com/TokTok/c-toxcore/pull/1413) Make afl_toxsave.c a bit more portable; fix memory leak. - [#1411](https://github.com/TokTok/c-toxcore/pull/1411) Fixes towards building on MSVC. - [#1409](https://github.com/TokTok/c-toxcore/pull/1409) Mark conference test as small. - [#1407](https://github.com/TokTok/c-toxcore/pull/1407) Add minimal save generator - [#1406](https://github.com/TokTok/c-toxcore/pull/1406) Migrate format-source script to new apidsl web app. - [#1404](https://github.com/TokTok/c-toxcore/pull/1404) Smarter setup of bazel remote cache on Cirrus CI. - [#1331](https://github.com/TokTok/c-toxcore/pull/1331) Add basic test adapter for AFL ### Closed issues: - [#1365](https://github.com/TokTok/c-toxcore/issues/1365) Add the option to use LAN discovery even when using a proxy for remote connections - [#1353](https://github.com/TokTok/c-toxcore/issues/1353) libtoxdns.a and libtoxav.a - [#86](https://github.com/TokTok/c-toxcore/issues/86) Freenet as Offline Messaging Backend ## v0.2.11 ### Merged PRs: - [#1405](https://github.com/TokTok/c-toxcore/pull/1405) Release 0.2.11 - [#1403](https://github.com/TokTok/c-toxcore/pull/1403) Install libsodium from apt instead of from source. - [#1402](https://github.com/TokTok/c-toxcore/pull/1402) Remove bazel build from Travis. - [#1400](https://github.com/TokTok/c-toxcore/pull/1400) Disable bazel remote cache on CI. - [#1399](https://github.com/TokTok/c-toxcore/pull/1399) Periodically try to send direct packets when connected by TCP. - [#1398](https://github.com/TokTok/c-toxcore/pull/1398) Minor cleanup: use `assoc_timeout` function where possible. - [#1397](https://github.com/TokTok/c-toxcore/pull/1397) Check that LOGGER macros are only called with string literals. - [#1396](https://github.com/TokTok/c-toxcore/pull/1396) Make function defns match their decls regarding storage class. - [#1395](https://github.com/TokTok/c-toxcore/pull/1395) Mark file-local function definitions as `static`. - [#1394](https://github.com/TokTok/c-toxcore/pull/1394) Enable remote cache for bazel builds. - [#1393](https://github.com/TokTok/c-toxcore/pull/1393) Add another bootstrap node to the bootstrap test. - [#1392](https://github.com/TokTok/c-toxcore/pull/1392) Clear out old conference connections. - [#1391](https://github.com/TokTok/c-toxcore/pull/1391) Minor cleanups in network code. - [#1390](https://github.com/TokTok/c-toxcore/pull/1390) Avoid casting back and forth between void-ptr. - [#1389](https://github.com/TokTok/c-toxcore/pull/1389) Standardise on having a comma at the end of enums. - [#1388](https://github.com/TokTok/c-toxcore/pull/1388) Fix up comments a bit to start being more uniform. - [#1387](https://github.com/TokTok/c-toxcore/pull/1387) Use rules_cc instead of native cc_library rules. - [#1386](https://github.com/TokTok/c-toxcore/pull/1386) Use spdx license identifier instead of GPL blurb. - [#1383](https://github.com/TokTok/c-toxcore/pull/1383) Pass packet ID to custom packet handlers. - [#1382](https://github.com/TokTok/c-toxcore/pull/1382) Add a mutex lock/unlock inside every public API function. - [#1381](https://github.com/TokTok/c-toxcore/pull/1381) Use `net_pack` instead of casting bytes to ints. - [#1380](https://github.com/TokTok/c-toxcore/pull/1380) Disable FreeBSD travis build until it is fixed. - [#1379](https://github.com/TokTok/c-toxcore/pull/1379) Update and fix FreeBSD setup on Travis-CI - [#1378](https://github.com/TokTok/c-toxcore/pull/1378) Use ninja build system for the cmake-linux build. - [#1376](https://github.com/TokTok/c-toxcore/pull/1376) Remove testing/av_test.c. - [#1375](https://github.com/TokTok/c-toxcore/pull/1375) Add "cimple_test" to the bazel build. - [#1374](https://github.com/TokTok/c-toxcore/pull/1374) Handle invite to existing conference - [#1372](https://github.com/TokTok/c-toxcore/pull/1372) Upgrade bazel to 2.1.1. - [#1371](https://github.com/TokTok/c-toxcore/pull/1371) Bump to astyle-3.1 in travis build. - [#1370](https://github.com/TokTok/c-toxcore/pull/1370) use -1 rather than ~0 in unsigned integer types - [#1362](https://github.com/TokTok/c-toxcore/pull/1362) Workaround for message number saving - [#1358](https://github.com/TokTok/c-toxcore/pull/1358) Allow Bazel to rerun tests marked as flaky - [#1352](https://github.com/TokTok/c-toxcore/pull/1352) Update tests to use a working bootstrap node - [#1349](https://github.com/TokTok/c-toxcore/pull/1349) Fix tox-bootstrapd's README and update Dockerfile - [#1347](https://github.com/TokTok/c-toxcore/pull/1347) Fix pthread_mutex_destroy getting too many arguments - [#1346](https://github.com/TokTok/c-toxcore/pull/1346) Fix most TSAN failures - [#1345](https://github.com/TokTok/c-toxcore/pull/1345) fix concurrency issues in mono_time - [#1343](https://github.com/TokTok/c-toxcore/pull/1343) Fix TSAN failures in tests - [#1334](https://github.com/TokTok/c-toxcore/pull/1334) fix missing group title length check - [#1330](https://github.com/TokTok/c-toxcore/pull/1330) Force IPv4 for cirrus-ci tests - [#1329](https://github.com/TokTok/c-toxcore/pull/1329) bump libsodium version in appveyor.yml - [#1322](https://github.com/TokTok/c-toxcore/pull/1322) Clean-up of group.c code - [#1321](https://github.com/TokTok/c-toxcore/pull/1321) Some small fixes to groups. - [#1299](https://github.com/TokTok/c-toxcore/pull/1299) Add VScode folder to .gitignore - [#1297](https://github.com/TokTok/c-toxcore/pull/1297) Use net_pack/unpack instead of host_to_net. ### Closed issues: - [#1373](https://github.com/TokTok/c-toxcore/issues/1373) handle crashes after group invites - [#1368](https://github.com/TokTok/c-toxcore/issues/1368) Are tox clients also open source - [#1366](https://github.com/TokTok/c-toxcore/issues/1366) Generate a link for websites (Friendship and proxy) - [#1354](https://github.com/TokTok/c-toxcore/issues/1354) Unstable Tests - [#1316](https://github.com/TokTok/c-toxcore/issues/1316) Documentation claims toxav_iteration_interval is threadsafe but it's not - [#1274](https://github.com/TokTok/c-toxcore/issues/1274) build error - [#850](https://github.com/TokTok/c-toxcore/issues/850) GPG App Usage ## v0.2.10 ### Merged PRs: - [#1324](https://github.com/TokTok/c-toxcore/pull/1324) Release 0.2.10 - [#1320](https://github.com/TokTok/c-toxcore/pull/1320) add undef guard in tox_many_tcp_test - [#1314](https://github.com/TokTok/c-toxcore/pull/1314) Fix bazel build version at 0.22.0 for CI. - [#1311](https://github.com/TokTok/c-toxcore/pull/1311) Disable failing TCP server test - [#1310](https://github.com/TokTok/c-toxcore/pull/1310) Do not send the same packet to the same node twice - [#1309](https://github.com/TokTok/c-toxcore/pull/1309) add configurable limit on number of stored frozen peers - [#1305](https://github.com/TokTok/c-toxcore/pull/1305) Expose api functions for enabling and disabling AV in AV groups - [#1302](https://github.com/TokTok/c-toxcore/pull/1302) Specify that buffer size for tox_conference_peer_get_name is given by $size ### Closed issues: - [#1325](https://github.com/TokTok/c-toxcore/issues/1325) Question: ETA of v0.2.10? - [#1313](https://github.com/TokTok/c-toxcore/issues/1313) CirrusCI is failing and blocking PRs - [#1312](https://github.com/TokTok/c-toxcore/issues/1312) Onion client review - [#1306](https://github.com/TokTok/c-toxcore/issues/1306) Persistent conference's offline peer list always grows and never decreases - [#1303](https://github.com/TokTok/c-toxcore/issues/1303) Loaded persistent groups fail to send audio - [#1298](https://github.com/TokTok/c-toxcore/issues/1298) How to make libtox4j-c.so for android? - [#1261](https://github.com/TokTok/c-toxcore/issues/1261) Bump so version - [#1116](https://github.com/TokTok/c-toxcore/issues/1116) Message length is too large log spam ## v0.2.9 ### Merged PRs: - [#1296](https://github.com/TokTok/c-toxcore/pull/1296) Add some const qualifiers - [#1295](https://github.com/TokTok/c-toxcore/pull/1295) Implement all min/max functions for (un)signed int types. - [#1293](https://github.com/TokTok/c-toxcore/pull/1293) Fix misaligned 4-byte access in trace logging. - [#1291](https://github.com/TokTok/c-toxcore/pull/1291) Use correct path to test log to cat on error. - [#1290](https://github.com/TokTok/c-toxcore/pull/1290) Display build log for autotools build on failure. - [#1289](https://github.com/TokTok/c-toxcore/pull/1289) Enable auto tests under STRICT_ABI if static libs are available. - [#1288](https://github.com/TokTok/c-toxcore/pull/1288) Add MIN_LOGGER_LEVEL to the Circle CI builds. - [#1287](https://github.com/TokTok/c-toxcore/pull/1287) Avoid sending group messages to a peer before we have its group number - [#1284](https://github.com/TokTok/c-toxcore/pull/1284) Use new WineHQ Debian package repository key - [#1283](https://github.com/TokTok/c-toxcore/pull/1283) Release 0.2.9 - [#1282](https://github.com/TokTok/c-toxcore/pull/1282) Merge irungentoo/master back into toktok/master. - [#1281](https://github.com/TokTok/c-toxcore/pull/1281) Allow unauthenticated wine packages in the Windows build. - [#1278](https://github.com/TokTok/c-toxcore/pull/1278) Add cmake option for building additional tests - [#1277](https://github.com/TokTok/c-toxcore/pull/1277) Define tox_conference_id_size and tox_conference_uid_size - [#1273](https://github.com/TokTok/c-toxcore/pull/1273) Avoid format truncation in save compatibility test - [#1272](https://github.com/TokTok/c-toxcore/pull/1272) Upgrade bazel to 0.19.0 to fix the bazel build. - [#1271](https://github.com/TokTok/c-toxcore/pull/1271) Return TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION if we are not connected to any peers - [#1268](https://github.com/TokTok/c-toxcore/pull/1268) Fix indices calculation for congestion control. - [#1267](https://github.com/TokTok/c-toxcore/pull/1267) Improve handling of peers entering and leaving conferences - [#1266](https://github.com/TokTok/c-toxcore/pull/1266) Expose offline conference peers in API - [#1242](https://github.com/TokTok/c-toxcore/pull/1242) Fix critical stack overflow arising from VLA usage - [#1239](https://github.com/TokTok/c-toxcore/pull/1239) Add some hopefully helpful documentation to the functions in mono_time.h - [#1235](https://github.com/TokTok/c-toxcore/pull/1235) Change method of PK production for FAKE friend in DHT - [#1234](https://github.com/TokTok/c-toxcore/pull/1234) Increase NOFILE limit for tox-bootstrapd - [#1231](https://github.com/TokTok/c-toxcore/pull/1231) Use `bool` for IPv6 flag in test programs and `DHT_bootstrap`. - [#1230](https://github.com/TokTok/c-toxcore/pull/1230) Add `LOGGER_ASSERT` for checking fatal error conditions. - [#1229](https://github.com/TokTok/c-toxcore/pull/1229) Include `CTest` in CMakeLists.txt to get valgrind support. - [#1228](https://github.com/TokTok/c-toxcore/pull/1228) Consistently use camel case enum names. - [#1223](https://github.com/TokTok/c-toxcore/pull/1223) Add AUTOTEST option to CMakeLists.txt - [#1221](https://github.com/TokTok/c-toxcore/pull/1221) Make tox-bootstrapd free memory on SIGINT and SIGTERM - [#1218](https://github.com/TokTok/c-toxcore/pull/1218) Support DragonFlyBSD and prune unused variables. - [#1215](https://github.com/TokTok/c-toxcore/pull/1215) Ensure save data unchanged after save and load - [#1213](https://github.com/TokTok/c-toxcore/pull/1213) Make saving and loading the responsibility of Tox rather than Messenger - [#1211](https://github.com/TokTok/c-toxcore/pull/1211) Some improvements to tox-bootstrapd's Dockerfile - [#1210](https://github.com/TokTok/c-toxcore/pull/1210) Remove Alpine Linux bootstrap daemon dockerfile. - [#1209](https://github.com/TokTok/c-toxcore/pull/1209) Improve Windows compatibility of toxav code. - [#1206](https://github.com/TokTok/c-toxcore/pull/1206) Add LAN_discovery to the list of apidsl-generated files. - [#1156](https://github.com/TokTok/c-toxcore/pull/1156) conferences saving ### Closed issues: - [#1285](https://github.com/TokTok/c-toxcore/issues/1285) Persistent group titles get mixed up - [#1276](https://github.com/TokTok/c-toxcore/issues/1276) How to run test case? - [#1275](https://github.com/TokTok/c-toxcore/issues/1275) Save file corruption - [#1269](https://github.com/TokTok/c-toxcore/issues/1269) Tox conference connected callback isn't triggered - [#1264](https://github.com/TokTok/c-toxcore/issues/1264) tox_conference_id_size() symbol missing - [#1262](https://github.com/TokTok/c-toxcore/issues/1262) Fails to build with STRICT_ABI option - [#1169](https://github.com/TokTok/c-toxcore/issues/1169) PK should not be generated with random_bytes - [#1143](https://github.com/TokTok/c-toxcore/issues/1143) Test #1081 - [#956](https://github.com/TokTok/c-toxcore/issues/956) friendlist access (add, delete, ...) causes crashes sometimes - [#777](https://github.com/TokTok/c-toxcore/issues/777) Proposal: TFCL [Tox Friend Capabilities Level] - [#762](https://github.com/TokTok/c-toxcore/issues/762) packet ranges not very clearly explained - [#743](https://github.com/TokTok/c-toxcore/issues/743) Proposal: reduce Video corruption even more by negotating the reference frame between sender and receiver - [#735](https://github.com/TokTok/c-toxcore/issues/735) Proposal: Tox MessageV2 - [#663](https://github.com/TokTok/c-toxcore/issues/663) libvpx vulnerability - [#626](https://github.com/TokTok/c-toxcore/issues/626) please add documentation to: bwcontroller.c - [#625](https://github.com/TokTok/c-toxcore/issues/625) function names misleading in ToxAV - [#617](https://github.com/TokTok/c-toxcore/issues/617) WIP: ToxIdenticon - howto - [#610](https://github.com/TokTok/c-toxcore/issues/610) PACKET_LOSSY_AV_RESERVED 8 # why? - [#609](https://github.com/TokTok/c-toxcore/issues/609) payload_type hardcoded - [#589](https://github.com/TokTok/c-toxcore/issues/589) running a normal tox node as tcp relay is not possible - [#584](https://github.com/TokTok/c-toxcore/issues/584) [INFO]: network graphs 0.1.9 vs 0.1.10 - [#548](https://github.com/TokTok/c-toxcore/issues/548) toxcore removes message receipts and filetransfers from memory, when client has short network outage - [#375](https://github.com/TokTok/c-toxcore/issues/375) Invalid bit rate prevents call ## v0.2.8 ### Merged PRs: - [#1225](https://github.com/TokTok/c-toxcore/pull/1225) Release 0.2.8 - [#1224](https://github.com/TokTok/c-toxcore/pull/1224) Avoid use of IPv6 in tests if not supported (e.g. on Travis). - [#1216](https://github.com/TokTok/c-toxcore/pull/1216) Fix memory leak in tcp server by wiping priority queues on deletion. - [#1212](https://github.com/TokTok/c-toxcore/pull/1212) Fix logger level defaulting to TRACE in CMake - [#1208](https://github.com/TokTok/c-toxcore/pull/1208) Remove a function-like macro and replace it with a function. - [#1205](https://github.com/TokTok/c-toxcore/pull/1205) Use a working DHT node for bootstrap tests. - [#1203](https://github.com/TokTok/c-toxcore/pull/1203) Revert "Improve cmake build for MSVC." - [#1202](https://github.com/TokTok/c-toxcore/pull/1202) Reset onion search rate for a friend when we see evidence that they are online - [#1199](https://github.com/TokTok/c-toxcore/pull/1199) Run tests on Appveyor (Windows native build). - [#1198](https://github.com/TokTok/c-toxcore/pull/1198) Add Cirrus CI configuration. - [#1197](https://github.com/TokTok/c-toxcore/pull/1197) Use new `@pthread` library from toktok-stack for Windows compat. - [#1196](https://github.com/TokTok/c-toxcore/pull/1196) Run UBSAN (undefined behaviour sanitizer) on Circle CI. - [#1195](https://github.com/TokTok/c-toxcore/pull/1195) Fix using uninitialized mutex on call end - [#1192](https://github.com/TokTok/c-toxcore/pull/1192) Send rejoin packets on conference disconnection - [#1191](https://github.com/TokTok/c-toxcore/pull/1191) Improve cmake build for MSVC - [#1188](https://github.com/TokTok/c-toxcore/pull/1188) Fix yamllint test (it's gone from bazel, add a new one). - [#1187](https://github.com/TokTok/c-toxcore/pull/1187) Fix typos in comments and log and test assertion messages. - [#1165](https://github.com/TokTok/c-toxcore/pull/1165) Fixed a silly boolean practice using uint8_t - [#1164](https://github.com/TokTok/c-toxcore/pull/1164) Format yaml files according to yamllint's requirements and remove branch filter for appveyor. - [#1161](https://github.com/TokTok/c-toxcore/pull/1161) Use most recent version of Bazel (0.17.1). - [#1158](https://github.com/TokTok/c-toxcore/pull/1158) Use C++ style casts in C++ code. - [#1157](https://github.com/TokTok/c-toxcore/pull/1157) Use run_auto_test fixture in typing_test.c - [#1155](https://github.com/TokTok/c-toxcore/pull/1155) Standardise header guards. - [#1154](https://github.com/TokTok/c-toxcore/pull/1154) Assert that we don't kill tox before killing toxav. - [#1153](https://github.com/TokTok/c-toxcore/pull/1153) Always use the passed logger (from Messenger) in msi_kill. - [#1151](https://github.com/TokTok/c-toxcore/pull/1151) Fix typo: tcp_replays -> tcp_relays. - [#1150](https://github.com/TokTok/c-toxcore/pull/1150) Use `(void)` for empty parameter lists in C. - [#1147](https://github.com/TokTok/c-toxcore/pull/1147) Ignore "unused-result" warning in super_donators code. - [#1145](https://github.com/TokTok/c-toxcore/pull/1145) Fix login issue on Travis-CI FreeBSD build - [#1141](https://github.com/TokTok/c-toxcore/pull/1141) Include necessary opencv2 header on OSX. - [#1140](https://github.com/TokTok/c-toxcore/pull/1140) Clean up `add_to_list` function a bit. - [#1139](https://github.com/TokTok/c-toxcore/pull/1139) Avoid recursion in `ip_is_lan` and `ip_is_local`. - [#1138](https://github.com/TokTok/c-toxcore/pull/1138) Add tool to find directly recursive calls in toxcore. - [#1136](https://github.com/TokTok/c-toxcore/pull/1136) Remove the use of `CLOCK_MONOTONIC_RAW`. - [#1135](https://github.com/TokTok/c-toxcore/pull/1135) Avoid use of global mutable state in mono_time on win32. - [#1134](https://github.com/TokTok/c-toxcore/pull/1134) Use `code font` for tool names and flags in INSTALL.md. - [#1126](https://github.com/TokTok/c-toxcore/pull/1126) Simplify configure.ac for faster autotools build. - [#1095](https://github.com/TokTok/c-toxcore/pull/1095) Use test clock in run_auto_test tests and dht test - [#1069](https://github.com/TokTok/c-toxcore/pull/1069) Add mechanism for recovering from disconnections in conferences - [#1046](https://github.com/TokTok/c-toxcore/pull/1046) Finish the messenger state plugin system - [#895](https://github.com/TokTok/c-toxcore/pull/895) Feature bootstrap trace/debug log output ### Closed issues: - [#1214](https://github.com/TokTok/c-toxcore/issues/1214) Massive red shutdown of nodes - [#1201](https://github.com/TokTok/c-toxcore/issues/1201) Windows cross-compilation is broken - [#1194](https://github.com/TokTok/c-toxcore/issues/1194) Cancelling unanswered toxav call locks uninitialied mutex - [#961](https://github.com/TokTok/c-toxcore/issues/961) Can't send messages in persistent group chat - [#960](https://github.com/TokTok/c-toxcore/issues/960) Persistent groups don't work properly when using toxync bot - [#838](https://github.com/TokTok/c-toxcore/issues/838) How to get groupchat identifier? ## v0.2.7 ### Merged PRs: - [#1142](https://github.com/TokTok/c-toxcore/pull/1142) Release 0.2.7 - [#1137](https://github.com/TokTok/c-toxcore/pull/1137) Make `ip_is_lan` return bool instead of 0/-1. - [#1133](https://github.com/TokTok/c-toxcore/pull/1133) Make the tsan build fail instead of swallowing its errors. - [#1132](https://github.com/TokTok/c-toxcore/pull/1132) Use `bool` in place of 0/1 int values. - [#1131](https://github.com/TokTok/c-toxcore/pull/1131) Format crypto_core.c. - [#1130](https://github.com/TokTok/c-toxcore/pull/1130) Fix test class name for mono_time_test. - [#1129](https://github.com/TokTok/c-toxcore/pull/1129) Call `abort` instead of `exit` on test failure. - [#1128](https://github.com/TokTok/c-toxcore/pull/1128) Add some tests for `ping_array`. - [#1127](https://github.com/TokTok/c-toxcore/pull/1127) Update copyright to 2018. - [#1125](https://github.com/TokTok/c-toxcore/pull/1125) Run save_compatibility_test in the autotools build. - [#1124](https://github.com/TokTok/c-toxcore/pull/1124) Fix the `PORT_ALLOC` failure of `save_compatibility_test`. - [#1123](https://github.com/TokTok/c-toxcore/pull/1123) Add support for setting a custom monotonic time function in mono_time - [#1122](https://github.com/TokTok/c-toxcore/pull/1122) Run all tests (and compilation) in parallel with autotools. - [#1120](https://github.com/TokTok/c-toxcore/pull/1120) Stop using massive macros in `toxav_basic_test`. - [#1119](https://github.com/TokTok/c-toxcore/pull/1119) Use do-while instead of while in tests. - [#1117](https://github.com/TokTok/c-toxcore/pull/1117) Fix leave callback calling in del_groupchat - [#1112](https://github.com/TokTok/c-toxcore/pull/1112) Fix auto_tests Makefile - [#1110](https://github.com/TokTok/c-toxcore/pull/1110) Add check to make sure tox was created successfully - [#1109](https://github.com/TokTok/c-toxcore/pull/1109) Consistently use 'mono_time' rather than 'monotime' - [#1107](https://github.com/TokTok/c-toxcore/pull/1107) Always print output on failure in cmake tests on Travis. - [#1106](https://github.com/TokTok/c-toxcore/pull/1106) Fix libmisc_tools building - [#1104](https://github.com/TokTok/c-toxcore/pull/1104) Avoid redefining macros from different files. - [#1103](https://github.com/TokTok/c-toxcore/pull/1103) Upload coverage to codecov as well as coveralls. - [#1102](https://github.com/TokTok/c-toxcore/pull/1102) Enable color diagnostics on circleci. - [#1101](https://github.com/TokTok/c-toxcore/pull/1101) Make the save_compatibility_test work with bazel. - [#1100](https://github.com/TokTok/c-toxcore/pull/1100) Make Mono_Time an argument to current_time_monotonic - [#1099](https://github.com/TokTok/c-toxcore/pull/1099) Fix const cast in save-generator. - [#1098](https://github.com/TokTok/c-toxcore/pull/1098) Run both asan and tsan on Circle CI. - [#1097](https://github.com/TokTok/c-toxcore/pull/1097) Run project tests like yamllint_test. - [#1096](https://github.com/TokTok/c-toxcore/pull/1096) Enable .travis.yml check and use non-markdown license. - [#1094](https://github.com/TokTok/c-toxcore/pull/1094) Set `_POSIX_C_SOURCE` to 200112L. We need it for C99 compat. - [#1092](https://github.com/TokTok/c-toxcore/pull/1092) Install the `DHT_bootstrap` binary on `make install`. - [#1086](https://github.com/TokTok/c-toxcore/pull/1086) Try ipv6 connections even after udp timeout - [#1081](https://github.com/TokTok/c-toxcore/pull/1081) Change while-loop to for-loop to express for-each-frame. - [#1075](https://github.com/TokTok/c-toxcore/pull/1075) Fix FreeBSD VM on Travis not shutting down - [#1061](https://github.com/TokTok/c-toxcore/pull/1061) Force storing the result of crypto_memcmp in the test. - [#1057](https://github.com/TokTok/c-toxcore/pull/1057) Reduce the number of times `unix_time_update` is called. - [#1051](https://github.com/TokTok/c-toxcore/pull/1051) Add save file generator, compatibility test, and generate a savefile - [#1038](https://github.com/TokTok/c-toxcore/pull/1038) Use per-instance `Mono_Time` instead of a global `unix_time` ### Closed issues: - [#1114](https://github.com/TokTok/c-toxcore/issues/1114) Segfault on group quit, free of invalid audio_decoder - [#1105](https://github.com/TokTok/c-toxcore/issues/1105) Sodium.h missing? ## v0.2.6 ### Merged PRs: - [#1093](https://github.com/TokTok/c-toxcore/pull/1093) Release 0.2.6 - [#1090](https://github.com/TokTok/c-toxcore/pull/1090) Fix possible resource leaks in test - [#1089](https://github.com/TokTok/c-toxcore/pull/1089) Limit the size of a save file in file_saving_test. - [#1088](https://github.com/TokTok/c-toxcore/pull/1088) Use `--config` to tell bazel about the environment. - [#1085](https://github.com/TokTok/c-toxcore/pull/1085) Prune long long warnings. - [#1084](https://github.com/TokTok/c-toxcore/pull/1084) Fix style in toxav.c. - [#1083](https://github.com/TokTok/c-toxcore/pull/1083) Fix coding style in rtp module. - [#1082](https://github.com/TokTok/c-toxcore/pull/1082) Fix groupav.c style and avoid casts in toxav_old.c. - [#1080](https://github.com/TokTok/c-toxcore/pull/1080) Fix memory leak in error path in group A/V. - [#1079](https://github.com/TokTok/c-toxcore/pull/1079) Fix style in video.c. - [#1078](https://github.com/TokTok/c-toxcore/pull/1078) Fix style in msi.c. - [#1077](https://github.com/TokTok/c-toxcore/pull/1077) Make `conferences_object` properly typed. - [#1076](https://github.com/TokTok/c-toxcore/pull/1076) Fix style in bwcontroller module. - [#1074](https://github.com/TokTok/c-toxcore/pull/1074) Move OSX to stage 1 of Travis. - [#1073](https://github.com/TokTok/c-toxcore/pull/1073) Stop running tests in the bazel build. - [#1072](https://github.com/TokTok/c-toxcore/pull/1072) Avoid forward declaration of rtp structs. - [#1071](https://github.com/TokTok/c-toxcore/pull/1071) Temporarily disable FreeBSD build, since it times out. - [#1070](https://github.com/TokTok/c-toxcore/pull/1070) Fix enumerator names in toxav to comply with toxcore naming standards. - [#1068](https://github.com/TokTok/c-toxcore/pull/1068) Fix a few warnings from clang. - [#1067](https://github.com/TokTok/c-toxcore/pull/1067) Remove last use of the `MIN` macro. - [#1066](https://github.com/TokTok/c-toxcore/pull/1066) Remove all uses of the PAIR macro in toxav. - [#1064](https://github.com/TokTok/c-toxcore/pull/1064) Fix ToxAv's use of `struct Tox`. - [#1063](https://github.com/TokTok/c-toxcore/pull/1063) Avoid passing -1 as friend connection to new groups. - [#1062](https://github.com/TokTok/c-toxcore/pull/1062) Check that the save file size isn't larger than our address space. - [#1060](https://github.com/TokTok/c-toxcore/pull/1060) Avoid implicit conversion of negative value to uint32_t. - [#1059](https://github.com/TokTok/c-toxcore/pull/1059) Assert that we don't divide by 0 in random_testing.cc. - [#1056](https://github.com/TokTok/c-toxcore/pull/1056) Fix typo in loop over assocs. - [#1053](https://github.com/TokTok/c-toxcore/pull/1053) Use tokstyle in the cmake travis build. - [#1049](https://github.com/TokTok/c-toxcore/pull/1049) Fix some printf format specifiers. - [#1043](https://github.com/TokTok/c-toxcore/pull/1043) Add simple deterministic random number generator for tests - [#1042](https://github.com/TokTok/c-toxcore/pull/1042) Add callback for successful connection to a conference - [#1039](https://github.com/TokTok/c-toxcore/pull/1039) Use the crypto random functions instead of `rand()`. - [#1036](https://github.com/TokTok/c-toxcore/pull/1036) Add deprecation notice to some UPPER_CASE enums. - [#1016](https://github.com/TokTok/c-toxcore/pull/1016) Split out conference type (text/av) from identifier. ## v0.2.5 ### Merged PRs: - [#1054](https://github.com/TokTok/c-toxcore/pull/1054) Release 0.2.5 - [#1048](https://github.com/TokTok/c-toxcore/pull/1048) Fix error message in m_send_generic_message - [#1047](https://github.com/TokTok/c-toxcore/pull/1047) Remove unused `m_callback_log` function. - [#1041](https://github.com/TokTok/c-toxcore/pull/1041) Avoid multiple for-next expressions. - [#1037](https://github.com/TokTok/c-toxcore/pull/1037) Run all tests in the Autotools build - [#1035](https://github.com/TokTok/c-toxcore/pull/1035) Fix problems with initial connections and name-setting in conferences - [#1032](https://github.com/TokTok/c-toxcore/pull/1032) Use auto_test fixture in some tests and standardise filenames - [#1030](https://github.com/TokTok/c-toxcore/pull/1030) Make a separate `struct Tox` containing the Messenger. - [#1029](https://github.com/TokTok/c-toxcore/pull/1029) Add `by_id` and `get_id` functions, renaming from `*_uid`. - [#1025](https://github.com/TokTok/c-toxcore/pull/1025) More fixed_width ints and incorporating file_saving_test.c - [#1023](https://github.com/TokTok/c-toxcore/pull/1023) Run buildifier on c-toxcore BUILD files. - [#1022](https://github.com/TokTok/c-toxcore/pull/1022) Make `resize` in `list.c` return bool instead of 0/1. - [#1021](https://github.com/TokTok/c-toxcore/pull/1021) Remove redundant casts to the same type. - [#1020](https://github.com/TokTok/c-toxcore/pull/1020) Add github usernames to TODOs. - [#1019](https://github.com/TokTok/c-toxcore/pull/1019) Synchronise parameter names in headers with those in the implementation. - [#1018](https://github.com/TokTok/c-toxcore/pull/1018) Reduce nesting by doing more early returns on error. - [#1017](https://github.com/TokTok/c-toxcore/pull/1017) Add missing braces in dht_test.c. - [#1011](https://github.com/TokTok/c-toxcore/pull/1011) Run Clang global static analysis on Travis. - [#1010](https://github.com/TokTok/c-toxcore/pull/1010) Avoid implementations in .h files or #including .c files. ### Closed issues: - [#1028](https://github.com/TokTok/c-toxcore/issues/1028) qTox crashes 1-2 times a day after update to 0.2.4 - [#1002](https://github.com/TokTok/c-toxcore/issues/1002) Implement an abstraction over pthread and windows thread synchronisation primitives ## v0.2.4 ### Merged PRs: - [#1024](https://github.com/TokTok/c-toxcore/pull/1024) Release v0.2.4 - [#1014](https://github.com/TokTok/c-toxcore/pull/1014) Use string comparison operator in configure.ac. - [#1013](https://github.com/TokTok/c-toxcore/pull/1013) Link -lsocket and -lnsl for socket functions on Solaris. - [#1012](https://github.com/TokTok/c-toxcore/pull/1012) Correct the max hostname length constant. - [#1009](https://github.com/TokTok/c-toxcore/pull/1009) Using stdint instead of int/long - [#1008](https://github.com/TokTok/c-toxcore/pull/1008) Set `_XOPEN_SOURCE` to 700 for FreeBSD. - [#1007](https://github.com/TokTok/c-toxcore/pull/1007) Use enums for group packet types. - [#1006](https://github.com/TokTok/c-toxcore/pull/1006) Set C++11/C99 flag manually in older cmake on not-msvc. - [#1005](https://github.com/TokTok/c-toxcore/pull/1005) Use the correct repository name in the coverage badge. - [#1003](https://github.com/TokTok/c-toxcore/pull/1003) Remove LOGGER_ERROR for harmless send failure. - [#1001](https://github.com/TokTok/c-toxcore/pull/1001) Add conference_by_uid and conference_get_uid functions. - [#1000](https://github.com/TokTok/c-toxcore/pull/1000) Limit number of group chats to 65536. - [#998](https://github.com/TokTok/c-toxcore/pull/998) Use named function types for group callbacks. - [#997](https://github.com/TokTok/c-toxcore/pull/997) Style fixes in TCP code; remove MIN and PAIR from util.h. - [#996](https://github.com/TokTok/c-toxcore/pull/996) Add the bazel build as one of the PR blocking builds. - [#995](https://github.com/TokTok/c-toxcore/pull/995) Fix style in some header files. - [#994](https://github.com/TokTok/c-toxcore/pull/994) Fix style in DHT.c. - [#993](https://github.com/TokTok/c-toxcore/pull/993) Move `load_state` and its helper functions to their own module. - [#991](https://github.com/TokTok/c-toxcore/pull/991) Use named function types for friend_connection callbacks. - [#990](https://github.com/TokTok/c-toxcore/pull/990) Use named function types for friend_requests callbacks. - [#989](https://github.com/TokTok/c-toxcore/pull/989) Use named function types for callbacks in net_crypto. - [#987](https://github.com/TokTok/c-toxcore/pull/987) Use named types for onion callbacks. - [#986](https://github.com/TokTok/c-toxcore/pull/986) Simplify Travis-CI FreeBSD build - [#985](https://github.com/TokTok/c-toxcore/pull/985) Clarify the intent of "file kinds" in the API. - [#984](https://github.com/TokTok/c-toxcore/pull/984) Avoid side-effectful assignments in conditionals. - [#981](https://github.com/TokTok/c-toxcore/pull/981) Factor out time keeping code into its own module: mono_time.c. - [#979](https://github.com/TokTok/c-toxcore/pull/979) Add a thread-safe version of unix_time and friends. - [#978](https://github.com/TokTok/c-toxcore/pull/978) Rename `BS_LIST` to `BS_List` to follow the naming conventions. - [#977](https://github.com/TokTok/c-toxcore/pull/977) Remove VLA usage from `send_audio_packet`. - [#976](https://github.com/TokTok/c-toxcore/pull/976) Call the "peer leaves" callback only once on group delete. - [#975](https://github.com/TokTok/c-toxcore/pull/975) Factor out the actual test code from conference_test. - [#972](https://github.com/TokTok/c-toxcore/pull/972) Add a test that reproduces the NULL peer nick bug. - [#968](https://github.com/TokTok/c-toxcore/pull/968) Make tox.c unambiguously parseable. - [#967](https://github.com/TokTok/c-toxcore/pull/967) lan_discovery_test and version_test cleanup - [#966](https://github.com/TokTok/c-toxcore/pull/966) Use run_auto_test.h test fixture for some auto-tests. - [#965](https://github.com/TokTok/c-toxcore/pull/965) Add `#include ` for `std::printf`. - [#964](https://github.com/TokTok/c-toxcore/pull/964) Add some tests for our ring_buffer implementation. - [#962](https://github.com/TokTok/c-toxcore/pull/962) Collect `PACKET_ID*` constants in `net_crypto.h`, cleanup their uses - [#958](https://github.com/TokTok/c-toxcore/pull/958) Fix leak of Logger instances in dht_test. - [#957](https://github.com/TokTok/c-toxcore/pull/957) Remove broken conference tests. - [#955](https://github.com/TokTok/c-toxcore/pull/955) Another TCP_test upgrade - [#954](https://github.com/TokTok/c-toxcore/pull/954) Proposal: Make arg `host` understand clearly. - [#953](https://github.com/TokTok/c-toxcore/pull/953) Add missing MAX_HOSTNAME_LENGTH doc. - [#945](https://github.com/TokTok/c-toxcore/pull/945) Add a test to try and overflow the send queue in net_crypto. - [#943](https://github.com/TokTok/c-toxcore/pull/943) Correct check for net_crypto packet index. - [#942](https://github.com/TokTok/c-toxcore/pull/942) Simplify Travis CI builds. - [#932](https://github.com/TokTok/c-toxcore/pull/932) Various minor cleanups in `net_crypto`. ### Closed issues: - [#1015](https://github.com/TokTok/c-toxcore/issues/1015) Improve Solaris support - [#1004](https://github.com/TokTok/c-toxcore/issues/1004) qTox: "Program received signal SIGPIPE, Broken pipe." with TokTok-c-toxcore-v0.2.3_GH0 on FreeBSD 11.x. - [#988](https://github.com/TokTok/c-toxcore/issues/988) Registration on https://nodes.tox.chat (question) - [#982](https://github.com/TokTok/c-toxcore/issues/982) Merge the two travis stages for freebsd back into one - [#970](https://github.com/TokTok/c-toxcore/issues/970) Crash with persistent groups - [#963](https://github.com/TokTok/c-toxcore/issues/963) ToxAV's `rb_write` function is written in a strange way - [#946](https://github.com/TokTok/c-toxcore/issues/946) [API] for max proxy address length - [#944](https://github.com/TokTok/c-toxcore/issues/944) How detect that friend is busy - [#936](https://github.com/TokTok/c-toxcore/issues/936) Help needed in testing a tox client,I need some dummy toxids to test . - [#923](https://github.com/TokTok/c-toxcore/issues/923) Crash on malloc in ping_array_add - [#911](https://github.com/TokTok/c-toxcore/issues/911) Weekly Tox Dev Meeting - [#910](https://github.com/TokTok/c-toxcore/issues/910) Crash in clear_entry in ping_array.c - [#903](https://github.com/TokTok/c-toxcore/issues/903) c-toxcore and LGPL (question) - [#528](https://github.com/TokTok/c-toxcore/issues/528) c-toxcore on Windows can be compiled using MSYS2 (with modern MinGW-w64) - [#472](https://github.com/TokTok/c-toxcore/issues/472) Crash in ping_array.c:35 - [#450](https://github.com/TokTok/c-toxcore/issues/450) Run format-test earlier in the build - [#429](https://github.com/TokTok/c-toxcore/issues/429) Cannot build on Windows using MinGW ## v0.2.3 ### Merged PRs: - [#952](https://github.com/TokTok/c-toxcore/pull/952) Release v0.2.3 - [#951](https://github.com/TokTok/c-toxcore/pull/951) Only run astyle if the astyle binary exists. - [#950](https://github.com/TokTok/c-toxcore/pull/950) Remove utils.c and utils.h from toxencryptsave build. - [#949](https://github.com/TokTok/c-toxcore/pull/949) Fixes to the imported sodium sources to compile without warnings. - [#948](https://github.com/TokTok/c-toxcore/pull/948) Add a MAX_HOSTNAME_LENGTH constant. - [#947](https://github.com/TokTok/c-toxcore/pull/947) Remove the format test. - [#937](https://github.com/TokTok/c-toxcore/pull/937) Add new Circle CI configuration. - [#935](https://github.com/TokTok/c-toxcore/pull/935) Add a test for double conference invite. - [#933](https://github.com/TokTok/c-toxcore/pull/933) Add Logger to various net_crypto functions, and add `const` to Logger where possible. - [#931](https://github.com/TokTok/c-toxcore/pull/931) Avoid conditional-uninitialised warning for tcp test. - [#930](https://github.com/TokTok/c-toxcore/pull/930) Disable UDP when proxy is enabled. - [#928](https://github.com/TokTok/c-toxcore/pull/928) Use clang-format for C++ code. - [#927](https://github.com/TokTok/c-toxcore/pull/927) Add assertions to bootstrap tests for correct connection type. - [#926](https://github.com/TokTok/c-toxcore/pull/926) Make NULL options behave the same as default options. - [#925](https://github.com/TokTok/c-toxcore/pull/925) Add tests for what happens when passing an invalid proxy host. - [#924](https://github.com/TokTok/c-toxcore/pull/924) Make the net_crypto connection state an enum. - [#922](https://github.com/TokTok/c-toxcore/pull/922) Clarify/Improve test_some test - [#921](https://github.com/TokTok/c-toxcore/pull/921) Beginnings of a TCP_test.c overhaul - [#920](https://github.com/TokTok/c-toxcore/pull/920) Add test for creating multiple conferences in one tox. - [#918](https://github.com/TokTok/c-toxcore/pull/918) Merge irungentoo/master into toktok - [#917](https://github.com/TokTok/c-toxcore/pull/917) Add random testing program. - [#916](https://github.com/TokTok/c-toxcore/pull/916) Fix linking with address sanitizer. - [#915](https://github.com/TokTok/c-toxcore/pull/915) Remove resource_leak_test. - [#914](https://github.com/TokTok/c-toxcore/pull/914) Make dht_test more stable. - [#913](https://github.com/TokTok/c-toxcore/pull/913) Minor cleanup: return early on error condition. - [#906](https://github.com/TokTok/c-toxcore/pull/906) Sort bazel build file according to buildifier standard. - [#905](https://github.com/TokTok/c-toxcore/pull/905) In DEBUG mode, make toxcore crash on signed integer overflow. - [#902](https://github.com/TokTok/c-toxcore/pull/902) Log only the filename, not the full path in LOGGER. - [#899](https://github.com/TokTok/c-toxcore/pull/899) Fix macOS macro because of GNU Mach - [#898](https://github.com/TokTok/c-toxcore/pull/898) Fix enumeration of Crypto_Connection instances - [#897](https://github.com/TokTok/c-toxcore/pull/897) Fix ipport_isset: port 0 is not a valid port. - [#894](https://github.com/TokTok/c-toxcore/pull/894) Fix logging related crash in bootstrap node - [#893](https://github.com/TokTok/c-toxcore/pull/893) Fix bootstrap crashes, still - [#892](https://github.com/TokTok/c-toxcore/pull/892) Add empty logger to DHT bootstrap daemons. - [#887](https://github.com/TokTok/c-toxcore/pull/887) Fix FreeBSD build on Travis - [#884](https://github.com/TokTok/c-toxcore/pull/884) Fix the often call of event tox_friend_connection_status - [#883](https://github.com/TokTok/c-toxcore/pull/883) Make toxcore compile on BSD - [#878](https://github.com/TokTok/c-toxcore/pull/878) fix DHT_bootstrap key loading - [#877](https://github.com/TokTok/c-toxcore/pull/877) Add minitox to under "Other resources" section in the README - [#875](https://github.com/TokTok/c-toxcore/pull/875) Make bootstrap daemon use toxcore's version - [#867](https://github.com/TokTok/c-toxcore/pull/867) Improve network error reporting on Windows - [#841](https://github.com/TokTok/c-toxcore/pull/841) Only check full rtp offset if RTP_LARGE_FRAME is set - [#823](https://github.com/TokTok/c-toxcore/pull/823) Finish @Diadlo's network Family abstraction. - [#822](https://github.com/TokTok/c-toxcore/pull/822) Move system header includes from network.h to network.c ### Closed issues: - [#900](https://github.com/TokTok/c-toxcore/issues/900) Log messages include the full build path - [#881](https://github.com/TokTok/c-toxcore/issues/881) Toxcore does not build with cmake on OpenBSD. - [#879](https://github.com/TokTok/c-toxcore/issues/879) DHT_bootstrap asserts due to no default logger - [#868](https://github.com/TokTok/c-toxcore/issues/868) A tox_friend_connection_status event often occurs ## v0.2.2 ### Merged PRs: - [#872](https://github.com/TokTok/c-toxcore/pull/872) Restrict packet kinds that can be sent through onion path. - [#864](https://github.com/TokTok/c-toxcore/pull/864) CMake warn if libconfig not found - [#863](https://github.com/TokTok/c-toxcore/pull/863) Remove broken and unmaintained scripts. - [#862](https://github.com/TokTok/c-toxcore/pull/862) Release v0.2.2 - [#859](https://github.com/TokTok/c-toxcore/pull/859) Add clarifying comment to cryptpacket_received function. - [#857](https://github.com/TokTok/c-toxcore/pull/857) Avoid the use of rand() in tests. - [#852](https://github.com/TokTok/c-toxcore/pull/852) bugfix build error on MacOS - [#846](https://github.com/TokTok/c-toxcore/pull/846) Disallow stderr logger by default. - [#845](https://github.com/TokTok/c-toxcore/pull/845) Fix coveralls reporting. - [#844](https://github.com/TokTok/c-toxcore/pull/844) Add COVERAGE cmake flag for clang. - [#825](https://github.com/TokTok/c-toxcore/pull/825) Add default stderr logger for logging to nullptr. - [#824](https://github.com/TokTok/c-toxcore/pull/824) Simplify sendpacket function, deduplicate some logic. - [#809](https://github.com/TokTok/c-toxcore/pull/809) Remove the use of the 'hh' format specifier. - [#801](https://github.com/TokTok/c-toxcore/pull/801) Add logging to the onion_test. - [#797](https://github.com/TokTok/c-toxcore/pull/797) Move struct DHT_Friend into DHT.c. ### Closed issues: - [#873](https://github.com/TokTok/c-toxcore/issues/873) Onion vulnerability - [#786](https://github.com/TokTok/c-toxcore/issues/786) Make format strings msvc/mingw-happy ## v0.2.1 ### Merged PRs: - [#839](https://github.com/TokTok/c-toxcore/pull/839) Update changelog for 0.2.1 - [#837](https://github.com/TokTok/c-toxcore/pull/837) Update version to 0.2.1. - [#833](https://github.com/TokTok/c-toxcore/pull/833) Add missing tox_nospam_size() function - [#832](https://github.com/TokTok/c-toxcore/pull/832) Don't set RTP_LARGE_FRAME on rtp audio packets - [#831](https://github.com/TokTok/c-toxcore/pull/831) Don't throw away rtp packets from old Toxcore - [#828](https://github.com/TokTok/c-toxcore/pull/828) Make file transfers 50% faster. ## v0.2.0 ### Merged PRs: - [#821](https://github.com/TokTok/c-toxcore/pull/821) Remove deprecated conference namelist change callback. - [#820](https://github.com/TokTok/c-toxcore/pull/820) Fix auto_tests to stop using the deprecated conference API. - [#819](https://github.com/TokTok/c-toxcore/pull/819) Change default username to empty string - [#818](https://github.com/TokTok/c-toxcore/pull/818) Change README to talk about cmake instead of autoreconf. - [#817](https://github.com/TokTok/c-toxcore/pull/817) Fix warning on Mac OS X and FreeBSD. - [#815](https://github.com/TokTok/c-toxcore/pull/815) Some minor cleanups suggested by cppcheck. - [#814](https://github.com/TokTok/c-toxcore/pull/814) Fix memory leak of Logger instance on error paths. - [#813](https://github.com/TokTok/c-toxcore/pull/813) Minor cleanups: dead stores and avoiding complex macros. - [#811](https://github.com/TokTok/c-toxcore/pull/811) Update changelog for 0.2.0 - [#808](https://github.com/TokTok/c-toxcore/pull/808) Fix a bunch of compiler warnings and remove suppressions. - [#807](https://github.com/TokTok/c-toxcore/pull/807) Link all tests to the android cpufeatures library if available. - [#806](https://github.com/TokTok/c-toxcore/pull/806) Fix toxcore.pc generation. - [#805](https://github.com/TokTok/c-toxcore/pull/805) Add an option that allows us to specify that we require toxav. - [#804](https://github.com/TokTok/c-toxcore/pull/804) Fix OSX tests: find(1) doesn't work like on Linux. - [#803](https://github.com/TokTok/c-toxcore/pull/803) Fix the windows build: pthread needs to be linked after vpx. - [#800](https://github.com/TokTok/c-toxcore/pull/800) Make group number in the toxav public API uint32_t - [#799](https://github.com/TokTok/c-toxcore/pull/799) Implement the "persistent conference" callback changes as new functions. - [#798](https://github.com/TokTok/c-toxcore/pull/798) Add deprecation notices to functions that will go away in v0.3.0. - [#796](https://github.com/TokTok/c-toxcore/pull/796) Make some sizeof tests linux-only. - [#794](https://github.com/TokTok/c-toxcore/pull/794) Remove apidsl from the build. - [#793](https://github.com/TokTok/c-toxcore/pull/793) Add a bazel test that ensures all our projects are GPL-3.0. - [#792](https://github.com/TokTok/c-toxcore/pull/792) Increase range of ports available to Toxes during tests - [#791](https://github.com/TokTok/c-toxcore/pull/791) Run all tests in parallel on Travis. - [#790](https://github.com/TokTok/c-toxcore/pull/790) Disable lan discovery in most tests. - [#789](https://github.com/TokTok/c-toxcore/pull/789) Remove tox_test from autotools build. - [#788](https://github.com/TokTok/c-toxcore/pull/788) Don't print trace level logging in tests. - [#787](https://github.com/TokTok/c-toxcore/pull/787) Split up tox_test into multiple smaller tests - [#784](https://github.com/TokTok/c-toxcore/pull/784) Use Wine Devel instead of Wine Staging - [#783](https://github.com/TokTok/c-toxcore/pull/783) Send 0 as peer number in CHANGE_OCCURRED group event. - [#782](https://github.com/TokTok/c-toxcore/pull/782) Use `const` more in C code. - [#781](https://github.com/TokTok/c-toxcore/pull/781) Don't build all the small sub-libraries. - [#780](https://github.com/TokTok/c-toxcore/pull/780) Get rid of the only GNU extension we used. - [#779](https://github.com/TokTok/c-toxcore/pull/779) Remove leftover symmetric key from DHT struct. - [#778](https://github.com/TokTok/c-toxcore/pull/778) Add static asserts for all the struct sizes in toxcore. - [#776](https://github.com/TokTok/c-toxcore/pull/776) Optionally use newer cmake features. - [#775](https://github.com/TokTok/c-toxcore/pull/775) Look for dependencies in third_party/ - [#774](https://github.com/TokTok/c-toxcore/pull/774) Improve gtest finding, support local checkout. - [#773](https://github.com/TokTok/c-toxcore/pull/773) Add gtest include directory to -I flags if found. - [#772](https://github.com/TokTok/c-toxcore/pull/772) Reject discovery packets coming from outside the "LAN". - [#771](https://github.com/TokTok/c-toxcore/pull/771) Adopt the "change occurred" API change from isotoxin-groupchat. - [#770](https://github.com/TokTok/c-toxcore/pull/770) Add MSVC compilation instructions - [#767](https://github.com/TokTok/c-toxcore/pull/767) Build toxcore with libsodium.dll instead of libsodium.lib. - [#766](https://github.com/TokTok/c-toxcore/pull/766) Remove libcheck from the dependencies. - [#765](https://github.com/TokTok/c-toxcore/pull/765) Make outgoing Filetransfers round-robin. - [#764](https://github.com/TokTok/c-toxcore/pull/764) Fix LAN discovery on FreeBSD. - [#761](https://github.com/TokTok/c-toxcore/pull/761) use official debian domain - [#760](https://github.com/TokTok/c-toxcore/pull/760) Make cmake script more forgiving. - [#759](https://github.com/TokTok/c-toxcore/pull/759) Use more ubuntu packages; remove hstox for now. - [#757](https://github.com/TokTok/c-toxcore/pull/757) Improve stability of crypto_memcmp test. - [#756](https://github.com/TokTok/c-toxcore/pull/756) Format .cpp files with format-source. - [#755](https://github.com/TokTok/c-toxcore/pull/755) Add some unit tests for util.h. - [#754](https://github.com/TokTok/c-toxcore/pull/754) Move the tox_sync tool to the toxins repository. - [#753](https://github.com/TokTok/c-toxcore/pull/753) Move irc_syncbot to the toxins repository. - [#752](https://github.com/TokTok/c-toxcore/pull/752) Move tox_shell program to the toxins repository. - [#751](https://github.com/TokTok/c-toxcore/pull/751) Use the markdown GPLv3 license in the c-toxcore repo. - [#750](https://github.com/TokTok/c-toxcore/pull/750) Remove csrc from the RTPHeader struct. - [#748](https://github.com/TokTok/c-toxcore/pull/748) Revert "Add correction message type" - [#745](https://github.com/TokTok/c-toxcore/pull/745) Change the "capabilities" field to a "flags" field. - [#742](https://github.com/TokTok/c-toxcore/pull/742) Improve conference test stability. - [#741](https://github.com/TokTok/c-toxcore/pull/741) Add `-D__STDC_LIMIT_MACROS=1` for C++ code. - [#739](https://github.com/TokTok/c-toxcore/pull/739) Add RTP header fields for the full frame length and offset. - [#737](https://github.com/TokTok/c-toxcore/pull/737) Use nullptr as NULL pointer constant instead of NULL or 0. - [#736](https://github.com/TokTok/c-toxcore/pull/736) Avoid clashes with "build" directories on case-insensitive file systems. - [#734](https://github.com/TokTok/c-toxcore/pull/734) Make audio/video bit rates "properties" - [#733](https://github.com/TokTok/c-toxcore/pull/733) Fix link in README.md - [#730](https://github.com/TokTok/c-toxcore/pull/730) Fix out of bounds read in error case in messenger_test. - [#729](https://github.com/TokTok/c-toxcore/pull/729) Remove dead return statement. - [#728](https://github.com/TokTok/c-toxcore/pull/728) Disable the autotools build in PR builds. - [#727](https://github.com/TokTok/c-toxcore/pull/727) Rename some rtp header struct members to be clearer. - [#725](https://github.com/TokTok/c-toxcore/pull/725) Publish a single public BUILD target for c-toxcore. - [#723](https://github.com/TokTok/c-toxcore/pull/723) Use for alloca on FreeBSD. - [#722](https://github.com/TokTok/c-toxcore/pull/722) Use self-built portaudio instead of system-provided. - [#721](https://github.com/TokTok/c-toxcore/pull/721) Manually serialise RTPHeader struct instead of memcpy. - [#718](https://github.com/TokTok/c-toxcore/pull/718) Improve sending of large video frames in toxav. - [#716](https://github.com/TokTok/c-toxcore/pull/716) Add comment from #629 in ring_buffer.c. - [#714](https://github.com/TokTok/c-toxcore/pull/714) Make BUILD files more finely-grained. - [#713](https://github.com/TokTok/c-toxcore/pull/713) Add BUILD files for all the little tools in the repo. - [#712](https://github.com/TokTok/c-toxcore/pull/712) Fix high quality video sending (backport to 0.1.x). - [#711](https://github.com/TokTok/c-toxcore/pull/711) Make the monolith test a C++ binary. - [#710](https://github.com/TokTok/c-toxcore/pull/710) Don't allocate or dereference Tox_Options in tests. - [#709](https://github.com/TokTok/c-toxcore/pull/709) Remove nTox from the repo. - [#708](https://github.com/TokTok/c-toxcore/pull/708) Add testing/*.c (except av_test) to bazel build. - [#707](https://github.com/TokTok/c-toxcore/pull/707) Fix log message in simple_conference_test: invite -> message. - [#705](https://github.com/TokTok/c-toxcore/pull/705) Add correction support for conference - [#703](https://github.com/TokTok/c-toxcore/pull/703) Add a simple conference test with 3 friends. - [#702](https://github.com/TokTok/c-toxcore/pull/702) Update to astyle 2.04 on CircleCI to get the correct result - [#701](https://github.com/TokTok/c-toxcore/pull/701) Add astyle to Circle CI build. - [#700](https://github.com/TokTok/c-toxcore/pull/700) Use more descriptive names in bwcontroller. - [#699](https://github.com/TokTok/c-toxcore/pull/699) Add some explanatory comments to the toxav audio code. - [#698](https://github.com/TokTok/c-toxcore/pull/698) Extract named constants from magic numbers in toxav/audio.c. - [#697](https://github.com/TokTok/c-toxcore/pull/697) Use C99 standard in bazel builds. - [#694](https://github.com/TokTok/c-toxcore/pull/694) Add bazel build scripts for c-toxcore. - [#693](https://github.com/TokTok/c-toxcore/pull/693) Make libcheck optional for windows builds. - [#691](https://github.com/TokTok/c-toxcore/pull/691) Don't install packages needlessly on Travis - [#690](https://github.com/TokTok/c-toxcore/pull/690) Run fewer Travis jobs during Pull Requests. - [#689](https://github.com/TokTok/c-toxcore/pull/689) Make Net_Crypto a module-private type. - [#688](https://github.com/TokTok/c-toxcore/pull/688) Make DHT a module-private type. - [#687](https://github.com/TokTok/c-toxcore/pull/687) Use apidsl to generate LAN_discovery.h. - [#686](https://github.com/TokTok/c-toxcore/pull/686) Remove hstox test for now. - [#685](https://github.com/TokTok/c-toxcore/pull/685) Add message type for correction - [#684](https://github.com/TokTok/c-toxcore/pull/684) Add random_u16 function and rename the others to match. - [#682](https://github.com/TokTok/c-toxcore/pull/682) Use larger arrays in crypto timing tests. - [#681](https://github.com/TokTok/c-toxcore/pull/681) Fix some memory or file descriptor leaks in test code. - [#680](https://github.com/TokTok/c-toxcore/pull/680) Filter out annoying log statements in unit tests. - [#679](https://github.com/TokTok/c-toxcore/pull/679) Use apidsl to generate ping.h. - [#678](https://github.com/TokTok/c-toxcore/pull/678) Sort monolith.h according to ls(1): uppercase first. - [#677](https://github.com/TokTok/c-toxcore/pull/677) Make pack/unpack_ip_port public DHT functions. - [#675](https://github.com/TokTok/c-toxcore/pull/675) Make Onion_Announce a module-private type. - [#674](https://github.com/TokTok/c-toxcore/pull/674) Make TCP_Client_Connection a module-private type. - [#673](https://github.com/TokTok/c-toxcore/pull/673) Move TCP_Secure_Connection from .h to .c file. - [#672](https://github.com/TokTok/c-toxcore/pull/672) Make Friend_Connections a module-private type. - [#670](https://github.com/TokTok/c-toxcore/pull/670) Make Friend_Requests a module-private type. - [#669](https://github.com/TokTok/c-toxcore/pull/669) Make Onion_Client a module-private type. - [#668](https://github.com/TokTok/c-toxcore/pull/668) Make Ping_Array a module-private type. - [#667](https://github.com/TokTok/c-toxcore/pull/667) pkg-config .pc files: added .private versions of Libs and Required - [#666](https://github.com/TokTok/c-toxcore/pull/666) Fix some typos in code and cmake comments - [#665](https://github.com/TokTok/c-toxcore/pull/665) Remove useless if statement - [#662](https://github.com/TokTok/c-toxcore/pull/662) Move Networking_Core struct into the .c file. - [#661](https://github.com/TokTok/c-toxcore/pull/661) Disable asan, since it seems to break on travis. - [#660](https://github.com/TokTok/c-toxcore/pull/660) Increase test retries to 10 (basically infinite). - [#659](https://github.com/TokTok/c-toxcore/pull/659) Fix formatting in some C files. - [#658](https://github.com/TokTok/c-toxcore/pull/658) Call freeaddrinfo on error paths in net_getipport. - [#657](https://github.com/TokTok/c-toxcore/pull/657) Zero-initialise stack-allocated objects in hstox driver. - [#656](https://github.com/TokTok/c-toxcore/pull/656) Fix file descriptor leak in hstox test. - [#654](https://github.com/TokTok/c-toxcore/pull/654) Bump toxcore version to 0.2.0. - [#652](https://github.com/TokTok/c-toxcore/pull/652) Add support for building the monolith test on android. - [#650](https://github.com/TokTok/c-toxcore/pull/650) Remove deprecated ToxDNS - [#648](https://github.com/TokTok/c-toxcore/pull/648) Make hstox compile on FreeBSD - [#624](https://github.com/TokTok/c-toxcore/pull/624) Update rpm spec and use variables in cmake instead of hardcoded paths - [#616](https://github.com/TokTok/c-toxcore/pull/616) Add projects link to Readme. - [#613](https://github.com/TokTok/c-toxcore/pull/613) Fix travis - [#605](https://github.com/TokTok/c-toxcore/pull/605) Fix OS X Travis. - [#598](https://github.com/TokTok/c-toxcore/pull/598) Fix typos in docs - [#578](https://github.com/TokTok/c-toxcore/pull/578) Split toxav_bit_rate_set() into two functions to hold the maximum bitrates libvpx supports - [#477](https://github.com/TokTok/c-toxcore/pull/477) Update install instructions to use CMake - [#465](https://github.com/TokTok/c-toxcore/pull/465) Add Alpine linux Dockerfile in addition to the existing Debian one - [#442](https://github.com/TokTok/c-toxcore/pull/442) Generate only one large library "libtoxcore". - [#334](https://github.com/TokTok/c-toxcore/pull/334) Change toxencryptsave API to never overwrite pass keys. ### Closed issues: - [#810](https://github.com/TokTok/c-toxcore/issues/810) Release 0.2.0 - [#704](https://github.com/TokTok/c-toxcore/issues/704) Add CORRECTION support to group chats - [#620](https://github.com/TokTok/c-toxcore/issues/620) Video bug: large video frames are not sent correctly - [#606](https://github.com/TokTok/c-toxcore/issues/606) groupId is int whereas friendId is uint32_t, reason? - [#599](https://github.com/TokTok/c-toxcore/issues/599) Error when linking against libtoxcore: undefined reference to symbol 'crypto_hash_sha256' - [#572](https://github.com/TokTok/c-toxcore/issues/572) int32_t may be not large enough as a argument for video_bit_rate of vp8/9 codec - [#566](https://github.com/TokTok/c-toxcore/issues/566) LAYER #: modules for static linking - build issue - [#383](https://github.com/TokTok/c-toxcore/issues/383) TODO: add cmake instructions in README.md - [#42](https://github.com/TokTok/c-toxcore/issues/42) Remove ToxDNS and related stuff from toxcore ## v0.1.11 ### Merged PRs: - [#643](https://github.com/TokTok/c-toxcore/pull/643) Add .editorconfig - [#638](https://github.com/TokTok/c-toxcore/pull/638) Release v0.1.11 - [#637](https://github.com/TokTok/c-toxcore/pull/637) Update tox-bootstrapd Dockerfile - [#635](https://github.com/TokTok/c-toxcore/pull/635) Separate FreeBSD Travis build in 2 stages - [#632](https://github.com/TokTok/c-toxcore/pull/632) Lift libconfig to v1.7.1 - [#631](https://github.com/TokTok/c-toxcore/pull/631) Add aspcud for Opam - [#630](https://github.com/TokTok/c-toxcore/pull/630) Fix for Travis fail on addr_resolve testing - [#623](https://github.com/TokTok/c-toxcore/pull/623) Split video payload into multiple RTP messages when too big to fit into one - [#615](https://github.com/TokTok/c-toxcore/pull/615) forget DHT pubkey of offline friend after DHT timeout - [#611](https://github.com/TokTok/c-toxcore/pull/611) Fix typo - [#607](https://github.com/TokTok/c-toxcore/pull/607) set onion pingid timeout to announce timeout (300s) - [#592](https://github.com/TokTok/c-toxcore/pull/592) Adjust docs of few toxencrypt function to the code - [#587](https://github.com/TokTok/c-toxcore/pull/587) Fix tox test - [#586](https://github.com/TokTok/c-toxcore/pull/586) Improve LAN discovery - [#576](https://github.com/TokTok/c-toxcore/pull/576) Replace include(CTest) on enable_testing() - [#574](https://github.com/TokTok/c-toxcore/pull/574) Reset hole-punching parameters after not punching for a while - [#571](https://github.com/TokTok/c-toxcore/pull/571) Configure needs to find libsodium headers. - [#515](https://github.com/TokTok/c-toxcore/pull/515) Network cleanup: reduce dependency on system-defined constants - [#505](https://github.com/TokTok/c-toxcore/pull/505) Add FreeBSD Travis - [#500](https://github.com/TokTok/c-toxcore/pull/500) Fixed the bug when receipts for messages sent from the receipt callback never arrived. ### Closed issues: - [#493](https://github.com/TokTok/c-toxcore/issues/493) Receipts for messages sent from the receipt callback never arrive - [#240](https://github.com/TokTok/c-toxcore/issues/240) Tox doesn't reconnect after internet connection interruption - [#237](https://github.com/TokTok/c-toxcore/issues/237) Contacts are shown offline when they are online ## v0.1.10 ### Merged PRs: - [#575](https://github.com/TokTok/c-toxcore/pull/575) Release v0.1.10 - [#564](https://github.com/TokTok/c-toxcore/pull/564) Fix Windows build - [#542](https://github.com/TokTok/c-toxcore/pull/542) Save bandwidth by moderating onion pinging ## v0.1.9 ### Merged PRs: - [#563](https://github.com/TokTok/c-toxcore/pull/563) Release v0.1.9 - [#561](https://github.com/TokTok/c-toxcore/pull/561) Remove unused variable - [#560](https://github.com/TokTok/c-toxcore/pull/560) Fix non-portable zeroing out of doubles - [#559](https://github.com/TokTok/c-toxcore/pull/559) Fix theoretical memory leaks - [#557](https://github.com/TokTok/c-toxcore/pull/557) Document inverted mutex lock/unlock. - [#556](https://github.com/TokTok/c-toxcore/pull/556) Build tests on appveyor, the MSVC build, but don't run them yet. - [#555](https://github.com/TokTok/c-toxcore/pull/555) Fold hstox tests into the general linux test. - [#554](https://github.com/TokTok/c-toxcore/pull/554) Add a monolith_test that includes all toxcore sources. - [#553](https://github.com/TokTok/c-toxcore/pull/553) Factor out strict_abi cmake code into a separate module. - [#552](https://github.com/TokTok/c-toxcore/pull/552) Fix formatting and spelling in version-sync script. - [#551](https://github.com/TokTok/c-toxcore/pull/551) Forbid undefined symbols in shared libraries. - [#546](https://github.com/TokTok/c-toxcore/pull/546) Make variable names in file saving test less cryptic - [#539](https://github.com/TokTok/c-toxcore/pull/539) Make OSX test failures fail the Travis CI build. - [#537](https://github.com/TokTok/c-toxcore/pull/537) Fix TokTok/c-toxcore#535 - [#534](https://github.com/TokTok/c-toxcore/pull/534) Fix markdown formatting - [#530](https://github.com/TokTok/c-toxcore/pull/530) Implement missing TES constant functions. - [#511](https://github.com/TokTok/c-toxcore/pull/511) Save bandwidth by avoiding superfluous Nodes Requests to peers already on the Close List - [#506](https://github.com/TokTok/c-toxcore/pull/506) Add test case for title change - [#498](https://github.com/TokTok/c-toxcore/pull/498) DHT refactoring - [#487](https://github.com/TokTok/c-toxcore/pull/487) Split daemon's logging backends in separate modules - [#468](https://github.com/TokTok/c-toxcore/pull/468) Test for memberlist not changing after changing own name - [#449](https://github.com/TokTok/c-toxcore/pull/449) Use new encoding of `Maybe` in msgpack results. ### Closed issues: - [#482](https://github.com/TokTok/c-toxcore/issues/482) CMake can't detect and compile ToxAV on OSX ## v0.1.8 ### Merged PRs: - [#538](https://github.com/TokTok/c-toxcore/pull/538) Reverting tox_loop PR changes - [#536](https://github.com/TokTok/c-toxcore/pull/536) Release v0.1.8 - [#526](https://github.com/TokTok/c-toxcore/pull/526) Add TOX_NOSPAM_SIZE to the public API. - [#525](https://github.com/TokTok/c-toxcore/pull/525) Retry autotools tests the same way as cmake tests. - [#524](https://github.com/TokTok/c-toxcore/pull/524) Reduce ctest timeout to 2 minutes from 5 minutes. - [#512](https://github.com/TokTok/c-toxcore/pull/512) Add test for DHT pack_nodes and unpack_nodes - [#504](https://github.com/TokTok/c-toxcore/pull/504) CMake: install bootstrapd if it is built - [#488](https://github.com/TokTok/c-toxcore/pull/488) Save compiled Android artifacts after CircleCI builds. - [#473](https://github.com/TokTok/c-toxcore/pull/473) Added missing includes: and - [#335](https://github.com/TokTok/c-toxcore/pull/335) Implement tox_loop ### Closed issues: - [#535](https://github.com/TokTok/c-toxcore/issues/535) OS X tests failing - [#503](https://github.com/TokTok/c-toxcore/issues/503) Undefined functions: tox_pass_salt_length, tox_pass_key_length, tox_pass_encryption_extra_length - [#456](https://github.com/TokTok/c-toxcore/issues/456) Tox.h doesn't expose the size of the nospam. - [#411](https://github.com/TokTok/c-toxcore/issues/411) Reduce CTest timeout to 2 minutes ## v0.1.7 ### Merged PRs: - [#523](https://github.com/TokTok/c-toxcore/pull/523) Release v0.1.7 - [#521](https://github.com/TokTok/c-toxcore/pull/521) Fix appveyor script: install curl from chocolatey. - [#510](https://github.com/TokTok/c-toxcore/pull/510) Fix list malloc(0) bug - [#509](https://github.com/TokTok/c-toxcore/pull/509) Fix network malloc(0) bug - [#497](https://github.com/TokTok/c-toxcore/pull/497) Fix network - [#496](https://github.com/TokTok/c-toxcore/pull/496) Fix Travis always succeeding despite tests failing - [#491](https://github.com/TokTok/c-toxcore/pull/491) Add crypto_memzero for temp buffer - [#490](https://github.com/TokTok/c-toxcore/pull/490) Move c_sleep to helpers.h and misc_tools.h - [#486](https://github.com/TokTok/c-toxcore/pull/486) Remove empty line in Messenger.c - [#483](https://github.com/TokTok/c-toxcore/pull/483) Make BUILD_TOXAV an option and fail if dependencies are missing - [#481](https://github.com/TokTok/c-toxcore/pull/481) Remove dependency on strings.h - [#480](https://github.com/TokTok/c-toxcore/pull/480) Use VLA macro - [#479](https://github.com/TokTok/c-toxcore/pull/479) Fix pthreads in AppVeyor build - [#471](https://github.com/TokTok/c-toxcore/pull/471) Remove statics used in onion comparison functions. - [#461](https://github.com/TokTok/c-toxcore/pull/461) Replace part of network functions on platform-independent implementation - [#452](https://github.com/TokTok/c-toxcore/pull/452) Add VLA compatibility macro for C89-ish compilers. ### Closed issues: - [#495](https://github.com/TokTok/c-toxcore/issues/495) Fix heap buffer overflow introduced by #461 - [#494](https://github.com/TokTok/c-toxcore/issues/494) Format networking code introduced by #461 - [#474](https://github.com/TokTok/c-toxcore/issues/474) TOX_VERSION_PATCH isn't in sync with the version ## v0.1.6 ### Merged PRs: - [#460](https://github.com/TokTok/c-toxcore/pull/460) Release v0.1.6. - [#459](https://github.com/TokTok/c-toxcore/pull/459) Add Android build to CI. - [#454](https://github.com/TokTok/c-toxcore/pull/454) Add appveyor build for native windows tests. - [#448](https://github.com/TokTok/c-toxcore/pull/448) Only retry failed tests on Circle CI instead of all. - [#434](https://github.com/TokTok/c-toxcore/pull/434) Replace redundant packet type check in handler with assert. - [#432](https://github.com/TokTok/c-toxcore/pull/432) Remove some static variables - [#385](https://github.com/TokTok/c-toxcore/pull/385) Add platform-independent Socket and IP implementation ### Closed issues: - [#457](https://github.com/TokTok/c-toxcore/issues/457) EPOLLRDHUP not defined in android ndk on lower API that 21 - [#415](https://github.com/TokTok/c-toxcore/issues/415) Set up a native windows build on appveyor ## v0.1.5 ### Merged PRs: - [#447](https://github.com/TokTok/c-toxcore/pull/447) Release v0.1.5. - [#446](https://github.com/TokTok/c-toxcore/pull/446) Limit number of retries to 3. - [#445](https://github.com/TokTok/c-toxcore/pull/445) Make Travis tests slightly more robust by re-running them. - [#443](https://github.com/TokTok/c-toxcore/pull/443) Make building `DHT_bootstrap` in cmake optional. - [#433](https://github.com/TokTok/c-toxcore/pull/433) Add tutorial and "danger: experimental" banner to README. - [#431](https://github.com/TokTok/c-toxcore/pull/431) Update license headers and remove redundant file name comment. - [#424](https://github.com/TokTok/c-toxcore/pull/424) Fixed the FreeBSD build failure due to the undefined MSG_NOSIGNAL. - [#420](https://github.com/TokTok/c-toxcore/pull/420) Setup autotools to read .so version info from a separate file - [#418](https://github.com/TokTok/c-toxcore/pull/418) Clarify how the autotools build is done on Travis. - [#414](https://github.com/TokTok/c-toxcore/pull/414) Explicitly check if compiler supports C99 ### Closed issues: - [#413](https://github.com/TokTok/c-toxcore/issues/413) Support C compilation with `-std=c99` in autotools ## v0.1.4 ### Merged PRs: - [#422](https://github.com/TokTok/c-toxcore/pull/422) Release v0.1.4. - [#410](https://github.com/TokTok/c-toxcore/pull/410) Fix NaCl build: tar was called incorrectly. - [#409](https://github.com/TokTok/c-toxcore/pull/409) Clarify that the pass key `new` function can fail. - [#407](https://github.com/TokTok/c-toxcore/pull/407) Don't use `git.depth=1` anymore. - [#404](https://github.com/TokTok/c-toxcore/pull/404) Issue 404: semicolon not found - [#403](https://github.com/TokTok/c-toxcore/pull/403) Warn on -pedantic, don't error yet. - [#401](https://github.com/TokTok/c-toxcore/pull/401) Add logging callback to messenger_test. - [#400](https://github.com/TokTok/c-toxcore/pull/400) Run windows tests but ignore their failures. - [#398](https://github.com/TokTok/c-toxcore/pull/398) Portability Fixes - [#397](https://github.com/TokTok/c-toxcore/pull/397) Replace make_quick_sort with qsort - [#396](https://github.com/TokTok/c-toxcore/pull/396) Add an OSX build that doesn't run tests. - [#394](https://github.com/TokTok/c-toxcore/pull/394) CMake: Add soversion to library files to generate proper symlinks - [#393](https://github.com/TokTok/c-toxcore/pull/393) Set up autotools build to build against vanilla NaCl. - [#392](https://github.com/TokTok/c-toxcore/pull/392) Check that TCP connections aren't dropped in callbacks. - [#391](https://github.com/TokTok/c-toxcore/pull/391) Minor simplification in `file_seek` code. - [#390](https://github.com/TokTok/c-toxcore/pull/390) Always kill invalid file transfers when receiving file controls. - [#388](https://github.com/TokTok/c-toxcore/pull/388) Fix logging condition for IPv6 client timestamp updates. - [#387](https://github.com/TokTok/c-toxcore/pull/387) Eliminate dead return statement. - [#386](https://github.com/TokTok/c-toxcore/pull/386) Avoid accessing uninitialised memory in `net_crypto`. - [#381](https://github.com/TokTok/c-toxcore/pull/381) Remove `TOX_DEBUG` and have asserts always enabled. ### Closed issues: - [#378](https://github.com/TokTok/c-toxcore/issues/378) Replace all uses of `make_quick_sort` with `qsort` - [#364](https://github.com/TokTok/c-toxcore/issues/364) Delete misc_tools.h after replacing its use by qsort. - [#363](https://github.com/TokTok/c-toxcore/issues/363) Test against NaCl in addition to libsodium on Travis. ## v0.1.3 ### Merged PRs: - [#395](https://github.com/TokTok/c-toxcore/pull/395) Revert "Portability fixes" - [#380](https://github.com/TokTok/c-toxcore/pull/380) Test a few cmake option combinations before the build. - [#377](https://github.com/TokTok/c-toxcore/pull/377) Fix SSL verification in coveralls. - [#376](https://github.com/TokTok/c-toxcore/pull/376) Bring back autotools instructions - [#373](https://github.com/TokTok/c-toxcore/pull/373) Only fetch 1 revision from git during Travis builds. - [#369](https://github.com/TokTok/c-toxcore/pull/369) Integrate with CircleCI to build artifacts in the future - [#366](https://github.com/TokTok/c-toxcore/pull/366) Release v0.1.3. - [#362](https://github.com/TokTok/c-toxcore/pull/362) Remove .cabal-sandbox option from tox-spectest find line. - [#361](https://github.com/TokTok/c-toxcore/pull/361) Simplify integration as a third-party lib in cmake projects - [#354](https://github.com/TokTok/c-toxcore/pull/354) Add secure memcmp and memzero implementation. - [#324](https://github.com/TokTok/c-toxcore/pull/324) Do not compile and install DHT_bootstrap if it was disabled in configure - [#297](https://github.com/TokTok/c-toxcore/pull/297) Portability fixes ### Closed issues: - [#347](https://github.com/TokTok/c-toxcore/issues/347) Implement our own secure `memcmp` and `memzero` if libsodium isn't available - [#319](https://github.com/TokTok/c-toxcore/issues/319) toxcore installs `DHT_bootstrap` even though `--disable-daemon` is passed to `./configure` ## v0.1.2 ### Merged PRs: - [#355](https://github.com/TokTok/c-toxcore/pull/355) Release v0.1.2 - [#353](https://github.com/TokTok/c-toxcore/pull/353) Fix toxav use after free caused by premature MSI destruction - [#346](https://github.com/TokTok/c-toxcore/pull/346) Avoid array out of bounds read in friend saving. - [#344](https://github.com/TokTok/c-toxcore/pull/344) Remove unused get/set salt/key functions from toxencryptsave. - [#343](https://github.com/TokTok/c-toxcore/pull/343) Wrap all sodium/nacl functions in crypto_core.c. - [#341](https://github.com/TokTok/c-toxcore/pull/341) Add test to check if tox_new/tox_kill leaks. - [#336](https://github.com/TokTok/c-toxcore/pull/336) Correct TES docs to reflect how many bytes functions actually require. - [#333](https://github.com/TokTok/c-toxcore/pull/333) Use `tox_options_set_*` instead of direct member access. ### Closed issues: - [#345](https://github.com/TokTok/c-toxcore/issues/345) Array out of bounds read in "save" function - [#342](https://github.com/TokTok/c-toxcore/issues/342) Wrap all libsodium functions we use in toxcore in `crypto_core`. - [#278](https://github.com/TokTok/c-toxcore/issues/278) ToxAV use-after-free bug ## v0.1.1 ### Merged PRs: - [#337](https://github.com/TokTok/c-toxcore/pull/337) Release v0.1.1 - [#332](https://github.com/TokTok/c-toxcore/pull/332) Add test for encrypted savedata. - [#330](https://github.com/TokTok/c-toxcore/pull/330) Strengthen the note about ABI compatibility in tox.h. - [#328](https://github.com/TokTok/c-toxcore/pull/328) Drop the broken `TOX_VERSION_REQUIRE` macro. - [#326](https://github.com/TokTok/c-toxcore/pull/326) Fix unresolved reference in toxencryptsave API docs. - [#309](https://github.com/TokTok/c-toxcore/pull/309) Fixed attempt to join detached threads (fixes toxav test crash) - [#306](https://github.com/TokTok/c-toxcore/pull/306) Add option to disable local peer discovery ### Closed issues: - [#327](https://github.com/TokTok/c-toxcore/issues/327) The `TOX_VERSION_REQUIRE` macro is broken. - [#221](https://github.com/TokTok/c-toxcore/issues/221) Option to disable local peer detection ## v0.1.0 ### Merged PRs: - [#325](https://github.com/TokTok/c-toxcore/pull/325) Fix Libs line in toxcore.pc pkg-config file. - [#322](https://github.com/TokTok/c-toxcore/pull/322) Add compatibility pkg-config modules: libtoxcore, libtoxav. - [#318](https://github.com/TokTok/c-toxcore/pull/318) Fix `--enable-logging` flag in autotools configure script. - [#316](https://github.com/TokTok/c-toxcore/pull/316) Release 0.1.0. - [#315](https://github.com/TokTok/c-toxcore/pull/315) Fix version compatibility test. - [#314](https://github.com/TokTok/c-toxcore/pull/314) Fix off by one error in saving our own status message. - [#313](https://github.com/TokTok/c-toxcore/pull/313) Fix padding being in the wrong place in `SAVED_FRIEND` struct - [#312](https://github.com/TokTok/c-toxcore/pull/312) Conditionally enable non-portable assert on LP64. - [#310](https://github.com/TokTok/c-toxcore/pull/310) Add apidsl file for toxencryptsave. - [#307](https://github.com/TokTok/c-toxcore/pull/307) Clarify toxencryptsave documentation regarding buffer sizes - [#305](https://github.com/TokTok/c-toxcore/pull/305) Fix static builds - [#303](https://github.com/TokTok/c-toxcore/pull/303) Don't build nTox by default. - [#301](https://github.com/TokTok/c-toxcore/pull/301) Renamed messenger functions, prepend `m_`. - [#299](https://github.com/TokTok/c-toxcore/pull/299) net_crypto give handle_data_packet_helper a better name - [#294](https://github.com/TokTok/c-toxcore/pull/294) Don't error on warnings by default ### Closed issues: - [#317](https://github.com/TokTok/c-toxcore/issues/317) toxcore fails to build with autotools and debugging level enabled - [#311](https://github.com/TokTok/c-toxcore/issues/311) Incorrect padding - [#308](https://github.com/TokTok/c-toxcore/issues/308) Review TES and port it to APIDSL - [#293](https://github.com/TokTok/c-toxcore/issues/293) error building on ubuntu 14.04 - [#292](https://github.com/TokTok/c-toxcore/issues/292) Don't build nTox by default with CMake - [#290](https://github.com/TokTok/c-toxcore/issues/290) User Feed - [#266](https://github.com/TokTok/c-toxcore/issues/266) Support all levels listed in TOX_DHT_NAT_LEVEL - [#216](https://github.com/TokTok/c-toxcore/issues/216) When v0.1 release? ## v0.0.5 ### Merged PRs: - [#289](https://github.com/TokTok/c-toxcore/pull/289) Version Patch v0.0.4 => v0.0.5 - [#287](https://github.com/TokTok/c-toxcore/pull/287) Add CMake knobs to suppress building tests - [#286](https://github.com/TokTok/c-toxcore/pull/286) Support float32 and float64 in msgpack type printer. - [#285](https://github.com/TokTok/c-toxcore/pull/285) Mark `Tox_Options` struct as deprecated. - [#284](https://github.com/TokTok/c-toxcore/pull/284) Add NONE enumerator to bit mask. - [#281](https://github.com/TokTok/c-toxcore/pull/281) Made save format platform-independent - [#277](https://github.com/TokTok/c-toxcore/pull/277) Fix a memory leak in hstox interface - [#276](https://github.com/TokTok/c-toxcore/pull/276) Fix NULL pointer dereference in log calls - [#275](https://github.com/TokTok/c-toxcore/pull/275) Fix a memory leak in GroupAV - [#274](https://github.com/TokTok/c-toxcore/pull/274) Options in `new_messenger()` must never be null. - [#271](https://github.com/TokTok/c-toxcore/pull/271) Convert to and from network byte order in set/get nospam. - [#262](https://github.com/TokTok/c-toxcore/pull/262) Add ability to disable UDP hole punching ### Closed issues: - [#254](https://github.com/TokTok/c-toxcore/issues/254) Add option to disable UDP hole punching - [#215](https://github.com/TokTok/c-toxcore/issues/215) The current tox save format is non-portable - [#205](https://github.com/TokTok/c-toxcore/issues/205) nospam value is reversed in array returned by `tox_self_get_address()` ## v0.0.4 ### Merged PRs: - [#272](https://github.com/TokTok/c-toxcore/pull/272) v0.0.4 - [#265](https://github.com/TokTok/c-toxcore/pull/265) Disable -Wunused-but-set-variable compiler warning flag. - [#261](https://github.com/TokTok/c-toxcore/pull/261) Work around Travis issue that causes build failures. - [#260](https://github.com/TokTok/c-toxcore/pull/260) Support arbitrary video resolutions in av_test - [#257](https://github.com/TokTok/c-toxcore/pull/257) Add decode/encode PlainText test support. - [#256](https://github.com/TokTok/c-toxcore/pull/256) Add spectest to the cmake test suite. - [#255](https://github.com/TokTok/c-toxcore/pull/255) Disable some gcc-specific warnings. - [#249](https://github.com/TokTok/c-toxcore/pull/249) Use apidsl for the crypto_core API. - [#248](https://github.com/TokTok/c-toxcore/pull/248) Remove new_nonce function in favour of random_nonce. - [#224](https://github.com/TokTok/c-toxcore/pull/224) Add DHT_create_packet, an abstraction for DHT RPC packets ## v0.0.3 ### Merged PRs: - [#251](https://github.com/TokTok/c-toxcore/pull/251) Rename log levels to remove the extra "LOG" prefix. - [#250](https://github.com/TokTok/c-toxcore/pull/250) Release v0.0.3. - [#245](https://github.com/TokTok/c-toxcore/pull/245) Change packet kind enum to use hex constants. - [#243](https://github.com/TokTok/c-toxcore/pull/243) Enable address sanitizer on the cmake build. - [#242](https://github.com/TokTok/c-toxcore/pull/242) Remove assoc - [#241](https://github.com/TokTok/c-toxcore/pull/241) Move log callback to options. - [#233](https://github.com/TokTok/c-toxcore/pull/233) Enable all possible C compiler warning flags. - [#230](https://github.com/TokTok/c-toxcore/pull/230) Move packing and unpacking DHT request packets to DHT module. - [#228](https://github.com/TokTok/c-toxcore/pull/228) Remove unimplemented "time delta" parameter. - [#227](https://github.com/TokTok/c-toxcore/pull/227) Compile as C++ for windows builds. - [#223](https://github.com/TokTok/c-toxcore/pull/223) TravisCI shorten IRC message - [#220](https://github.com/TokTok/c-toxcore/pull/220) toxav renaming: group.{h,c} -> groupav.{h,c} - [#218](https://github.com/TokTok/c-toxcore/pull/218) Rename some internal "group chat" thing to "conference". - [#212](https://github.com/TokTok/c-toxcore/pull/212) Convert series of `NET_PACKET_*` defines into a typedef enum - [#196](https://github.com/TokTok/c-toxcore/pull/196) Update readme, moved the roadmap to a higher position - [#193](https://github.com/TokTok/c-toxcore/pull/193) Remove duplicate tests: split tests part 2. ### Closed issues: - [#40](https://github.com/TokTok/c-toxcore/issues/40) Stateless callbacks in toxcore's public API ## v0.0.2 ### Merged PRs: - [#207](https://github.com/TokTok/c-toxcore/pull/207) docs: correct instructions for cloning & harden against repo name changes - [#206](https://github.com/TokTok/c-toxcore/pull/206) Corrected libsodium tag - [#204](https://github.com/TokTok/c-toxcore/pull/204) Error if format_test can't be executed. - [#202](https://github.com/TokTok/c-toxcore/pull/202) Version Patch v0.0.2 - [#190](https://github.com/TokTok/c-toxcore/pull/190) Install libraries with RPATH. - [#189](https://github.com/TokTok/c-toxcore/pull/189) Use `socklen_t` instead of `unsigned int` in call to `accept`. - [#188](https://github.com/TokTok/c-toxcore/pull/188) Add option to set test timeout - [#187](https://github.com/TokTok/c-toxcore/pull/187) Add option to build tox-bootstrapd - [#185](https://github.com/TokTok/c-toxcore/pull/185) Import the hstox SUT interface from hstox. - [#183](https://github.com/TokTok/c-toxcore/pull/183) Set log level for DEBUG=ON to LOG_DEBUG. - [#182](https://github.com/TokTok/c-toxcore/pull/182) Remove return after no-return situation. - [#181](https://github.com/TokTok/c-toxcore/pull/181) Minor documentation fixes. - [#180](https://github.com/TokTok/c-toxcore/pull/180) Add the 'Tox' context object to the logger. - [#179](https://github.com/TokTok/c-toxcore/pull/179) Remove the `_test` suffix in `auto_test` calls. - [#178](https://github.com/TokTok/c-toxcore/pull/178) Rebuild apidsl'd headers in cmake. - [#177](https://github.com/TokTok/c-toxcore/pull/177) docs(INSTALL): update compiling instructions for Linux - [#176](https://github.com/TokTok/c-toxcore/pull/176) Merge irungentoo/toxcore into TokTok/c-toxcore. - [#173](https://github.com/TokTok/c-toxcore/pull/173) Duplicate tox_test to 4 other files. ### Closed issues: - [#201](https://github.com/TokTok/c-toxcore/issues/201) Logging callback was broken ## v0.0.1 ### Merged PRs: - [#174](https://github.com/TokTok/c-toxcore/pull/174) Remove redundant callback objects. - [#171](https://github.com/TokTok/c-toxcore/pull/171) Simple Version tick to v0.0.1 - [#170](https://github.com/TokTok/c-toxcore/pull/170) C++ the second round. - [#166](https://github.com/TokTok/c-toxcore/pull/166) Add version-sync script. - [#164](https://github.com/TokTok/c-toxcore/pull/164) Replace `void*` with `RingBuffer*` to avoid conversions. - [#163](https://github.com/TokTok/c-toxcore/pull/163) Move ring buffer out of toxcore/util into toxav. - [#162](https://github.com/TokTok/c-toxcore/pull/162) Allow the OSX build to fail on travis. - [#161](https://github.com/TokTok/c-toxcore/pull/161) Minor cleanups: unused vars, unreachable code, static globals. - [#160](https://github.com/TokTok/c-toxcore/pull/160) Work around bug in opencv3 headers. - [#157](https://github.com/TokTok/c-toxcore/pull/157) Make TCP_Connections module-private. - [#156](https://github.com/TokTok/c-toxcore/pull/156) Make TCP_Server opaque. - [#153](https://github.com/TokTok/c-toxcore/pull/153) Fix strict-ld grep expressions to include digits. - [#151](https://github.com/TokTok/c-toxcore/pull/151) Revert #130 "Make ToxAV stateless" - [#148](https://github.com/TokTok/c-toxcore/pull/148) Added UB comment r/t deleting a friend w/ active call - [#146](https://github.com/TokTok/c-toxcore/pull/146) Make group callbacks stateless - [#145](https://github.com/TokTok/c-toxcore/pull/145) Make internal chat list function take uint32_t* as well. - [#144](https://github.com/TokTok/c-toxcore/pull/144) Only build toxav if opus and vpx are found. - [#143](https://github.com/TokTok/c-toxcore/pull/143) Make toxcore code C++ compatible. - [#142](https://github.com/TokTok/c-toxcore/pull/142) Fix for windows dynamic libraries. - [#141](https://github.com/TokTok/c-toxcore/pull/141) const-correctness in windows code. - [#140](https://github.com/TokTok/c-toxcore/pull/140) Use C99 %zu format conversion in printf for size_t. - [#139](https://github.com/TokTok/c-toxcore/pull/139) Clean up Travis build a bit in preparation for osx/win. - [#138](https://github.com/TokTok/c-toxcore/pull/138) Remove format-source from travis script. - [#135](https://github.com/TokTok/c-toxcore/pull/135) Convert old groupchats to new API format - [#134](https://github.com/TokTok/c-toxcore/pull/134) Add some astyle options to make it do more. - [#133](https://github.com/TokTok/c-toxcore/pull/133) Ensure that all TODOs have an owner. - [#132](https://github.com/TokTok/c-toxcore/pull/132) Remove `else` directly after `return`. - [#130](https://github.com/TokTok/c-toxcore/pull/130) Make ToxAV stateless - [#129](https://github.com/TokTok/c-toxcore/pull/129) Use TokTok's apidsl instead of the iphydf one. - [#127](https://github.com/TokTok/c-toxcore/pull/127) Use "phase" script for travis build phases. - [#126](https://github.com/TokTok/c-toxcore/pull/126) Add option to build static libraries. - [#125](https://github.com/TokTok/c-toxcore/pull/125) Group #include directives in 3-4 groups. - [#123](https://github.com/TokTok/c-toxcore/pull/123) Use correct logical operator for tox_test - [#120](https://github.com/TokTok/c-toxcore/pull/120) make the majority of the callbacks stateless and add some status to a testcase - [#118](https://github.com/TokTok/c-toxcore/pull/118) Use `const` for version numbers. - [#117](https://github.com/TokTok/c-toxcore/pull/117) Add STRICT_ABI cmake flag to generate export lists. - [#116](https://github.com/TokTok/c-toxcore/pull/116) Fix potential null pointer dereference. - [#115](https://github.com/TokTok/c-toxcore/pull/115) Fix memory leak on error paths in tox_new. - [#114](https://github.com/TokTok/c-toxcore/pull/114) Fix compilation for Windows. - [#111](https://github.com/TokTok/c-toxcore/pull/111) Add debugging option to autotools configuration - [#110](https://github.com/TokTok/c-toxcore/pull/110) Comment intentional switch fallthroughs - [#109](https://github.com/TokTok/c-toxcore/pull/109) Separate ip_port packing from pack_nodes() and unpack_nodes() - [#108](https://github.com/TokTok/c-toxcore/pull/108) Prevent `` inclusion by ``. - [#107](https://github.com/TokTok/c-toxcore/pull/107) Print a message about missing astyle in format-source. - [#104](https://github.com/TokTok/c-toxcore/pull/104) Merge with irungentoo/master - [#103](https://github.com/TokTok/c-toxcore/pull/103) Allocate `sizeof(IP_ADAPTER_INFO)` bytes instead of `sizeof(T*)`. - [#101](https://github.com/TokTok/c-toxcore/pull/101) Add TODO for @mannol. - [#100](https://github.com/TokTok/c-toxcore/pull/100) Remove the packet mutation in toxav's bwcontroller. - [#99](https://github.com/TokTok/c-toxcore/pull/99) Make packet data a ptr-to-const. - [#97](https://github.com/TokTok/c-toxcore/pull/97) Improve static and const correctness. - [#96](https://github.com/TokTok/c-toxcore/pull/96) Improve C standard compliance. - [#94](https://github.com/TokTok/c-toxcore/pull/94) Rearrange fields to decrease size of structure - [#84](https://github.com/TokTok/c-toxcore/pull/84) Remove useless casts. - [#82](https://github.com/TokTok/c-toxcore/pull/82) Add missing #include to av_test.c. - [#81](https://github.com/TokTok/c-toxcore/pull/81) Match parameter names in declarations with their definitions. - [#80](https://github.com/TokTok/c-toxcore/pull/80) Sort #includes in all source files. - [#79](https://github.com/TokTok/c-toxcore/pull/79) Remove redundant `return` statements. - [#78](https://github.com/TokTok/c-toxcore/pull/78) Do not use `else` after `return`. - [#77](https://github.com/TokTok/c-toxcore/pull/77) Add OSX and Windows build to travis config. - [#76](https://github.com/TokTok/c-toxcore/pull/76) Remove unused and bit-rotten friends_test. - [#75](https://github.com/TokTok/c-toxcore/pull/75) Enable build of av_test. - [#74](https://github.com/TokTok/c-toxcore/pull/74) Add missing #includes to headers and rename tox_old to tox_group. - [#73](https://github.com/TokTok/c-toxcore/pull/73) Add braces to all if statements. - [#72](https://github.com/TokTok/c-toxcore/pull/72) Add getters/setters for options. - [#70](https://github.com/TokTok/c-toxcore/pull/70) Expose constants as functions. - [#68](https://github.com/TokTok/c-toxcore/pull/68) Add address sanitizer option to cmake file. - [#66](https://github.com/TokTok/c-toxcore/pull/66) Fix plane size calculation in test - [#65](https://github.com/TokTok/c-toxcore/pull/65) Avoid large stack allocations on thread stacks. - [#64](https://github.com/TokTok/c-toxcore/pull/64) Comment out useless TODO'd if block. - [#63](https://github.com/TokTok/c-toxcore/pull/63) Initialise the id in assoc_test. - [#62](https://github.com/TokTok/c-toxcore/pull/62) Reduce the timeout on travis to something much more reasonable - [#60](https://github.com/TokTok/c-toxcore/pull/60) Make friend requests stateless - [#59](https://github.com/TokTok/c-toxcore/pull/59) Replace uint with unsigned int in assoc.c. - [#58](https://github.com/TokTok/c-toxcore/pull/58) Make Message received receipts stateless - [#57](https://github.com/TokTok/c-toxcore/pull/57) Make Friend User Status stateless - [#55](https://github.com/TokTok/c-toxcore/pull/55) docs(INSTALL.md): update instructions for Gentoo - [#54](https://github.com/TokTok/c-toxcore/pull/54) Make typing change callback stateless - [#53](https://github.com/TokTok/c-toxcore/pull/53) Add format-source script. - [#52](https://github.com/TokTok/c-toxcore/pull/52) Build assoc DHT code on travis. - [#51](https://github.com/TokTok/c-toxcore/pull/51) Fix operation sequencing in TCP_test. - [#49](https://github.com/TokTok/c-toxcore/pull/49) Apidsl test - [#48](https://github.com/TokTok/c-toxcore/pull/48) Make friend message callback stateless - [#46](https://github.com/TokTok/c-toxcore/pull/46) Move logging to a callback. - [#45](https://github.com/TokTok/c-toxcore/pull/45) Stateless friend status message - [#43](https://github.com/TokTok/c-toxcore/pull/43) Allow NULL as argument to tox_kill. - [#41](https://github.com/TokTok/c-toxcore/pull/41) Fix warnings - [#39](https://github.com/TokTok/c-toxcore/pull/39) Merge irungentoo/toxcore into TokTok/c-toxcore. - [#38](https://github.com/TokTok/c-toxcore/pull/38) Try searching for libsodium with pkg-config in ./configure. - [#37](https://github.com/TokTok/c-toxcore/pull/37) Add missing DHT_bootstrap to CMakeLists.txt. - [#36](https://github.com/TokTok/c-toxcore/pull/36) Make tox_callback_friend_name stateless. - [#33](https://github.com/TokTok/c-toxcore/pull/33) Update readme with tentative roadmap, removed old todo.md - [#32](https://github.com/TokTok/c-toxcore/pull/32) Fix a bug I introduced that would make toxcore fail to initialise a second time - [#31](https://github.com/TokTok/c-toxcore/pull/31) 7. Travis envs - [#30](https://github.com/TokTok/c-toxcore/pull/30) 2. Hstox test - [#29](https://github.com/TokTok/c-toxcore/pull/29) 1. Move toxcore travis build scripts out of .travis.yml. - [#27](https://github.com/TokTok/c-toxcore/pull/27) 8. Stateless - [#26](https://github.com/TokTok/c-toxcore/pull/26) 6. Cmake bootstrapd - [#25](https://github.com/TokTok/c-toxcore/pull/25) 5. Coverage clang - [#24](https://github.com/TokTok/c-toxcore/pull/24) Silence/fix some compiler warnings. - [#23](https://github.com/TokTok/c-toxcore/pull/23) 4. Cmake - [#20](https://github.com/TokTok/c-toxcore/pull/20) 3. Travis astyle - [#13](https://github.com/TokTok/c-toxcore/pull/13) Enable, and report test status - [#12](https://github.com/TokTok/c-toxcore/pull/12) Fix readme for TokTok - [#11](https://github.com/TokTok/c-toxcore/pull/11) Documentation: SysVInit workaround for <1024 ports - [#2](https://github.com/TokTok/c-toxcore/pull/2) Enable toxcore logging when building on Travis. - [#1](https://github.com/TokTok/c-toxcore/pull/1) Apidsl fixes and start tracking test coverage ### Closed issues: - [#158](https://github.com/TokTok/c-toxcore/issues/158) Error while build with OpenCV 3.1 - [#147](https://github.com/TokTok/c-toxcore/issues/147) Add comment to m_delfriend about the NULL passing to the internal conn status cb - [#136](https://github.com/TokTok/c-toxcore/issues/136) Replace astyle by clang-format - [#113](https://github.com/TokTok/c-toxcore/issues/113) Toxcore tests fail - [#83](https://github.com/TokTok/c-toxcore/issues/83) Travis tests are hard to quickly parse from their output. - [#22](https://github.com/TokTok/c-toxcore/issues/22) Make the current tests exercise both ipv4 and ipv6. - [#9](https://github.com/TokTok/c-toxcore/issues/9) Fix the failing test - [#8](https://github.com/TokTok/c-toxcore/issues/8) Toxcore should make more liberal use of assertions - [#4](https://github.com/TokTok/c-toxcore/issues/4) Integrate hstox tests with toxcore Travis build c-toxcore-0.2.20/cmake/0000755060175106017510000000000014714247532012557 5ustar robinc-toxcore-0.2.20/cmake/Dependencies.cmake0000644060175106017510000000177014714247532016154 0ustar robin############################################################################### # # :: For systems that have pkg-config. # ############################################################################### find_package(PkgConfig REQUIRED) find_library(NSL_LIBRARIES nsl ) find_library(RT_LIBRARIES rt ) find_library(SOCKET_LIBRARIES socket) find_package(pthreads QUIET) if(NOT TARGET PThreads4W::PThreads4W) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) endif() # For toxcore. pkg_search_module(LIBSODIUM libsodium IMPORTED_TARGET REQUIRED) if(MSVC) find_package(unofficial-sodium REQUIRED) endif() # For toxav. pkg_search_module(OPUS opus IMPORTED_TARGET) if(NOT OPUS_FOUND) pkg_search_module(OPUS Opus IMPORTED_TARGET) endif() pkg_search_module(VPX vpx IMPORTED_TARGET) if(NOT VPX_FOUND) pkg_search_module(VPX libvpx IMPORTED_TARGET) endif() # For tox-bootstrapd. pkg_search_module(LIBCONFIG libconfig IMPORTED_TARGET) c-toxcore-0.2.20/cmake/MacRpath.cmake0000644060175106017510000000173614714247532015267 0ustar robin# Taken from https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH. # # In many cases you will want to make sure that the required libraries are # always found independent from LD_LIBRARY_PATH and the install location. Then # you can use these settings: # Use, i.e. don't skip the full RPATH for the build tree. set(CMAKE_SKIP_BUILD_RPATH FALSE) # When building, don't use the install RPATH already # (but later on when installing). set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # Add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH. set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # The RPATH to be used when installing, but only if it's not a system directory. list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") endif() c-toxcore-0.2.20/cmake/ModulePackage.cmake0000644060175106017510000000366214714247532016271 0ustar robinoption(ENABLE_SHARED "Build shared (dynamic) libraries for all modules" ON) option(ENABLE_STATIC "Build static libraries for all modules" ON) if(NOT ENABLE_SHARED AND NOT ENABLE_STATIC) message(WARNING "Both static and shared libraries are disabled; " "enabling only shared libraries. Use -DENABLE_SHARED or -DENABLE_STATIC to " "select one manually.") set(ENABLE_SHARED ON) endif() option(FULLY_STATIC "Build fully static executables" OFF) if(FULLY_STATIC) set(CMAKE_EXE_LINKER_FLAGS "-static -no-pie") # remove -Wl,-Bdynamic set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS) set(ENABLE_SHARED OFF) set(ENABLE_STATIC ON) endif() function(install_module lib) if(TARGET ${lib}_shared) set_target_properties(${lib}_shared PROPERTIES VERSION ${SOVERSION} SOVERSION ${SOVERSION_MAJOR} ) install(TARGETS ${lib}_shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() if(TARGET ${lib}_static) install(TARGETS ${lib}_static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() string(REPLACE ";" " " ${lib}_PKGCONFIG_LIBS "${${lib}_PKGCONFIG_LIBS}") string(REPLACE ";" " " ${lib}_PKGCONFIG_REQUIRES "${${lib}_PKGCONFIG_REQUIRES}") configure_file( "${${lib}_SOURCE_DIR}/other/pkgconfig/${lib}.pc.in" "${CMAKE_BINARY_DIR}/${lib}.pc" @ONLY ) configure_file( "${toxcore_SOURCE_DIR}/other/rpm/${lib}.spec.in" "${CMAKE_BINARY_DIR}/${lib}.spec" @ONLY ) install(FILES ${CMAKE_BINARY_DIR}/${lib}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) foreach(sublib ${${lib}_API_HEADERS}) string(REPLACE "^" ";" sublib ${sublib}) list(GET sublib 0 header) install(FILES ${header} ${ARGN}) endforeach() endfunction() c-toxcore-0.2.20/cmake/StrictAbi.cmake0000644060175106017510000000454014714247532015450 0ustar robin################################################################################ # # :: Strict ABI # # Enabling the STRICT_ABI flag will generate and use an LD version script. # It ensures that the dynamic libraries (libtoxcore.so, libtoxav.so) only # export the symbols that are defined in their public API (tox.h and toxav.h, # respectively). # ################################################################################ find_program(SHELL NAMES sh dash bash zsh fish) macro(make_version_script) if(STRICT_ABI AND SHELL AND ENABLE_SHARED) _make_version_script(${ARGN}) endif() endmacro() function(_make_version_script target) set(${target}_VERSION_SCRIPT "${CMAKE_BINARY_DIR}/${target}.ld") file(WRITE ${${target}_VERSION_SCRIPT} "{ global:\n") foreach(sublib ${ARGN}) string(REPLACE "^" ";" sublib ${sublib}) list(GET sublib 0 header) list(GET sublib 1 ns) execute_process( COMMAND ${SHELL} -c "egrep '^\\w' ${header} | grep '${ns}_[a-z0-9_]*(' | grep -v '^typedef' | grep -o '${ns}_[a-z0-9_]*(' | egrep -o '[a-z0-9_]+' | sort -u" OUTPUT_VARIABLE sublib_SYMS OUTPUT_STRIP_TRAILING_WHITESPACE) string(REPLACE "\n" ";" sublib_SYMS ${sublib_SYMS}) foreach(sym ${sublib_SYMS}) file(APPEND ${${target}_VERSION_SCRIPT} "${sym};\n") endforeach(sym) endforeach(sublib) file(APPEND ${${target}_VERSION_SCRIPT} "local: *; };\n") set_target_properties(${target}_shared PROPERTIES LINK_FLAGS -Wl,--version-script,${${target}_VERSION_SCRIPT}) endfunction() option(STRICT_ABI "Enforce strict ABI export in dynamic libraries" OFF) if((WIN32 AND NOT MINGW) OR APPLE) # Windows and macOS don't have this linker functionality. set(STRICT_ABI OFF) endif() if(STRICT_ABI AND NOT ENABLE_STATIC) if(AUTOTEST) message("AUTOTEST option is incompatible with STRICT_ABI. Disabling AUTOTEST.") endif() set(AUTOTEST OFF) if(BUILD_MISC_TESTS) message("BUILD_MISC_TESTS option is incompatible with STRICT_ABI. Disabling BUILD_MISC_TESTS.") endif() set(BUILD_MISC_TESTS OFF) if(BOOTSTRAP_DAEMON) message("BOOTSTRAP_DAEMON option is incompatible with STRICT_ABI. Disabling BOOTSTRAP_DAEMON.") endif() set(BOOTSTRAP_DAEMON OFF) if(DHT_BOOTSTRAP) message("DHT_BOOTSTRAP option is incompatible with STRICT_ABI. Disabling DHT_BOOTSTRAP.") endif() set(DHT_BOOTSTRAP OFF) endif() c-toxcore-0.2.20/CMakeLists.txt0000644060175106017510000005244014714247532014244 0ustar robin################################################################################ # # The main toxcore CMake build file. # # This file when processed with cmake produces: # - A number of small libraries (.a/.so/...) containing independent components # of toxcore. E.g. the DHT has its own library, and the system/network # abstractions are in their own library as well. These libraries are not # installed on `make install`. The toxav, and toxencryptsave libraries are # also not installed. # - A number of small programs, statically linked if possible. # - One big library containing all of the toxcore, toxav, and toxencryptsave # code. # ################################################################################ cmake_minimum_required(VERSION 3.16) cmake_policy(VERSION 3.16) project(toxcore) list(APPEND CMAKE_MODULE_PATH ${toxcore_SOURCE_DIR}/cmake) option(FLAT_OUTPUT_STRUCTURE "Whether to produce output artifacts in ${CMAKE_BINARY_DIR}/{bin,lib}" OFF) if(FLAT_OUTPUT_STRUCTURE) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) endif() set_source_files_properties( toxcore/mono_time.c toxcore/network.c toxcore/tox.c toxcore/util.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) ################################################################################ # # :: Version management # ################################################################################ # This version is for the entire project. All libraries (core, av, ...) move in # versions in a synchronised way. set(PROJECT_VERSION_MAJOR "0") set(PROJECT_VERSION_MINOR "2") set(PROJECT_VERSION_PATCH "20") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") # set .so library version / following libtool scheme # https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_CURRENT REGEX "^CURRENT=[0-9]+$") string(SUBSTRING "${SOVERSION_CURRENT}" 8 -1 SOVERSION_CURRENT) file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_REVISION REGEX "^REVISION=[0-9]+$") string(SUBSTRING "${SOVERSION_REVISION}" 9 -1 SOVERSION_REVISION) file(STRINGS ${toxcore_SOURCE_DIR}/so.version SOVERSION_AGE REGEX "^AGE=[0-9]+$") string(SUBSTRING "${SOVERSION_AGE}" 4 -1 SOVERSION_AGE) # account for some libtool magic, see other/version-sync script for details math(EXPR SOVERSION_MAJOR ${SOVERSION_CURRENT}-${SOVERSION_AGE}) set(SOVERSION "${SOVERSION_MAJOR}.${SOVERSION_AGE}.${SOVERSION_REVISION}") message("SOVERSION: ${SOVERSION}") ################################################################################ # # :: Dependencies and configuration # ################################################################################ include(CTest) include(ModulePackage) include(StrictAbi) include(GNUInstallDirs) if(APPLE) include(MacRpath) endif() enable_testing() find_package(GTest) set(CMAKE_MACOSX_RPATH ON) # Set standard version for compiler. if(MSVC AND MSVC_TOOLSET_VERSION LESS 143) # https://developercommunity.visualstudio.com/t/older-winsdk-headers-are-incompatible-with-zcprepr/1593479 set(CMAKE_C_STANDARD 99) else() set(CMAKE_C_STANDARD 11) endif() set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF) message(STATUS "Supported C compiler features = ${CMAKE_C_COMPILE_FEATURES}") message(STATUS "Supported C++ compiler features = ${CMAKE_CXX_COMPILE_FEATURES}") # Enable some warnings if we know the compiler. if(MSVC) add_compile_options(/W4 /analyze) add_compile_options(/wd4100) # unreferenced formal parameter add_compile_options(/wd4267) # narrowing conversion add_compile_options(/wd4244) # narrowing conversion add_compile_options(/wd4127) # conditional expression is constant add_compile_options(/wd4995) # #pragma deprecated add_compile_options(/wd4018) # signed/unsigned compare add_compile_options(/wd4310) # cast truncates constant value add_compile_options(/wd4389) # signed/unsigned compare add_compile_options(/wd4245) # signed/unsigned assign/return/function call add_compile_options(/wd4200) # nonstandard extension used: zero-sized array in struct/union add_compile_options(/wd4702) # unreachable code add_compile_options(/wd6340) # unsigned int passed to signed parameter add_compile_options(/wd6326) # potential comparison of a constant with another constant # TODO(iphydf): Look into these add_compile_options(/wd4996) # use WSAAddressToStringW() instead of WSAAddressToStringA() add_compile_options(/wd6255) # don't use alloca add_compile_options(/wd6385) # reading invalid data add_compile_options(/wd6001) # using uninitialized memory add_compile_options(/wd6101) # returning uninitialized memory add_compile_options(/wd6386) # buffer overrun add_compile_options(/wd6011) # NULL dereference add_compile_options(/wd6031) # sscanf return value ignored add_compile_options(/wd6387) # passing NULL to fwrite endif() set(MIN_LOGGER_LEVEL "" CACHE STRING "Logging level to use (TRACE, DEBUG, INFO, WARNING, ERROR)") if(MIN_LOGGER_LEVEL) if(("${MIN_LOGGER_LEVEL}" STREQUAL "TRACE") OR ("${MIN_LOGGER_LEVEL}" STREQUAL "DEBUG") OR ("${MIN_LOGGER_LEVEL}" STREQUAL "INFO") OR ("${MIN_LOGGER_LEVEL}" STREQUAL "WARNING") OR ("${MIN_LOGGER_LEVEL}" STREQUAL "ERROR")) add_definitions(-DMIN_LOGGER_LEVEL=LOGGER_LEVEL_${MIN_LOGGER_LEVEL}) else() message(FATAL_ERROR "Unknown value provided for MIN_LOGGER_LEVEL: \"${MIN_LOGGER_LEVEL}\", must be one of TRACE, DEBUG, INFO, WARNING or ERROR") endif() endif() option(EXPERIMENTAL_API "Install experimental header file with unstable API" OFF) option(USE_IPV6 "Use IPv6 in tests" ON) if(NOT USE_IPV6) add_definitions(-DUSE_IPV6=0) endif() option(BUILD_MISC_TESTS "Build additional tests" OFF) option(BUILD_FUN_UTILS "Build additional just for fun utilities" OFF) option(UNITTEST "Enable unit tests (disable if you don't have a working gmock or gtest)" ON) option(AUTOTEST "Enable autotests (mainly for CI)" OFF) if(AUTOTEST) option(NON_HERMETIC_TESTS "Whether to build and run tests that depend on an internet connection" OFF) option(PROXY_TEST "Enable proxy test (requires other/proxy/proxy_server.go to be running)" OFF) endif() option(BUILD_TOXAV "Whether to build the tox AV library" ON) option(MUST_BUILD_TOXAV "Fail the build if toxav cannot be built" OFF) option(DHT_BOOTSTRAP "Enable building of DHT_bootstrap" ON) option(BOOTSTRAP_DAEMON "Enable building of tox-bootstrapd" ON) if(BOOTSTRAP_DAEMON AND WIN32) message(WARNING "Building tox-bootstrapd for Windows is not supported, disabling") set(BOOTSTRAP_DAEMON OFF CACHE BOOL "" FORCE) endif() option(BUILD_FUZZ_TESTS "Build fuzzing harnesses" OFF) if(MSVC) option(MSVC_STATIC_SODIUM "Whether to link libsodium statically for MSVC" OFF) if(MSVC_STATIC_SODIUM) add_definitions(-DSODIUM_STATIC=1) endif() endif() include(Dependencies) if(MUST_BUILD_TOXAV) set(NO_TOXAV_ERROR_TYPE SEND_ERROR) set(BUILD_TOXAV ON CACHE BOOL "" FORCE) else() set(NO_TOXAV_ERROR_TYPE WARNING) endif() if(BUILD_TOXAV) if(NOT OPUS_FOUND) message(${NO_TOXAV_ERROR_TYPE} "Option BUILD_TOXAV is enabled but required library OPUS was not found.") set(BUILD_TOXAV OFF CACHE BOOL "" FORCE) endif() if(NOT VPX_FOUND) message(${NO_TOXAV_ERROR_TYPE} "Option BUILD_TOXAV is enabled but required library VPX was not found.") set(BUILD_TOXAV OFF CACHE BOOL "" FORCE) endif() endif() # Disable float/double packing in CMP (C MessagePack library). # We don't transfer floats over the network, so we disable this functionality. add_definitions(-DCMP_NO_FLOAT=1) ################################################################################ # # :: Tox Core Library # ################################################################################ # toxcore_PKGCONFIG_LIBS is what's added to the Libs: line in toxcore.pc. It # needs to contain all the libraries a program using toxcore should link against # if it's statically linked. If it's dynamically linked, there is no need to # explicitly link against all the dependencies, but it doesn't harm much(*) # either. # # (*) It allows client code to use symbols from our dependencies without # explicitly linking against them. set(toxcore_PKGCONFIG_LIBS) # Requires: in pkg-config file. set(toxcore_PKGCONFIG_REQUIRES) set(toxcore_SOURCES third_party/cmp/cmp.c third_party/cmp/cmp.h toxcore/announce.c toxcore/announce.h toxcore/bin_pack.c toxcore/bin_pack.h toxcore/bin_unpack.c toxcore/bin_unpack.h toxcore/ccompat.c toxcore/ccompat.h toxcore/crypto_core.c toxcore/crypto_core.h toxcore/crypto_core_pack.c toxcore/crypto_core_pack.h toxcore/DHT.c toxcore/DHT.h toxcore/events/conference_connected.c toxcore/events/conference_invite.c toxcore/events/conference_message.c toxcore/events/conference_peer_list_changed.c toxcore/events/conference_peer_name.c toxcore/events/conference_title.c toxcore/events/dht_get_nodes_response.c toxcore/events/events_alloc.c toxcore/events/events_alloc.h toxcore/events/file_chunk_request.c toxcore/events/file_recv.c toxcore/events/file_recv_chunk.c toxcore/events/file_recv_control.c toxcore/events/friend_connection_status.c toxcore/events/friend_lossless_packet.c toxcore/events/friend_lossy_packet.c toxcore/events/friend_message.c toxcore/events/friend_name.c toxcore/events/friend_read_receipt.c toxcore/events/friend_request.c toxcore/events/friend_status.c toxcore/events/friend_status_message.c toxcore/events/friend_typing.c toxcore/events/self_connection_status.c toxcore/events/group_custom_packet.c toxcore/events/group_custom_private_packet.c toxcore/events/group_invite.c toxcore/events/group_join_fail.c toxcore/events/group_message.c toxcore/events/group_moderation.c toxcore/events/group_password.c toxcore/events/group_peer_exit.c toxcore/events/group_peer_join.c toxcore/events/group_peer_limit.c toxcore/events/group_peer_name.c toxcore/events/group_peer_status.c toxcore/events/group_privacy_state.c toxcore/events/group_private_message.c toxcore/events/group_self_join.c toxcore/events/group_topic.c toxcore/events/group_topic_lock.c toxcore/events/group_voice_state.c toxcore/forwarding.c toxcore/forwarding.h toxcore/friend_connection.c toxcore/friend_connection.h toxcore/friend_requests.c toxcore/friend_requests.h toxcore/group.c toxcore/group_chats.c toxcore/group_chats.h toxcore/group_common.h toxcore/group_connection.c toxcore/group_connection.h toxcore/group.h toxcore/group_announce.c toxcore/group_announce.h toxcore/group_moderation.c toxcore/group_moderation.h toxcore/group_onion_announce.c toxcore/group_onion_announce.h toxcore/group_pack.c toxcore/group_pack.h toxcore/LAN_discovery.c toxcore/LAN_discovery.h toxcore/list.c toxcore/list.h toxcore/logger.c toxcore/logger.h toxcore/Messenger.c toxcore/Messenger.h toxcore/mem.c toxcore/mem.h toxcore/mono_time.c toxcore/mono_time.h toxcore/net_crypto.c toxcore/net_crypto.h toxcore/network.c toxcore/network.h toxcore/onion_announce.c toxcore/onion_announce.h toxcore/onion.c toxcore/onion_client.c toxcore/onion_client.h toxcore/onion.h toxcore/ping_array.c toxcore/ping_array.h toxcore/ping.c toxcore/ping.h toxcore/shared_key_cache.c toxcore/shared_key_cache.h toxcore/state.c toxcore/state.h toxcore/TCP_client.c toxcore/TCP_client.h toxcore/TCP_common.c toxcore/TCP_common.h toxcore/TCP_connection.c toxcore/TCP_connection.h toxcore/TCP_server.c toxcore/TCP_server.h toxcore/timed_auth.c toxcore/timed_auth.h toxcore/tox_api.c toxcore/tox.c toxcore/tox_dispatch.c toxcore/tox_dispatch.h toxcore/tox_event.c toxcore/tox_event.h toxcore/tox_events.c toxcore/tox_events.h toxcore/tox.h toxcore/tox_private.c toxcore/tox_private.h toxcore/tox_pack.c toxcore/tox_pack.h toxcore/tox_unpack.c toxcore/tox_unpack.h toxcore/util.c toxcore/util.h) if(TARGET unofficial-sodium::sodium) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} unofficial-sodium::sodium) else() set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${LIBSODIUM_LIBRARIES}) set(toxcore_LINK_DIRECTORIES ${toxcore_LINK_DIRECTORIES} ${LIBSODIUM_LIBRARY_DIRS}) set(toxcore_INCLUDE_DIRECTORIES ${toxcore_INCLUDE_DIRECTORIES} ${LIBSODIUM_INCLUDE_DIRS}) set(toxcore_COMPILE_OPTIONS ${toxcore_COMPILE_OPTIONS} ${LIBSODIUM_CFLAGS_OTHER}) endif() set(toxcore_PKGCONFIG_REQUIRES ${toxcore_PKGCONFIG_REQUIRES} libsodium) set(toxcore_API_HEADERS ${toxcore_SOURCE_DIR}/toxcore/tox.h^tox ${toxcore_SOURCE_DIR}/toxcore/tox_events.h^tox ${toxcore_SOURCE_DIR}/toxcore/tox_dispatch.h^tox) if(EXPERIMENTAL_API) set(toxcore_API_HEADERS ${toxcore_API_HEADERS} ${toxcore_SOURCE_DIR}/toxcore/tox_private.h^tox) endif() ################################################################################ # # :: Audio/Video Library # ################################################################################ if(BUILD_TOXAV) set(toxcore_SOURCES ${toxcore_SOURCES} toxav/audio.c toxav/audio.h toxav/bwcontroller.c toxav/bwcontroller.h toxav/groupav.c toxav/groupav.h toxav/msi.c toxav/msi.h toxav/ring_buffer.c toxav/ring_buffer.h toxav/rtp.c toxav/rtp.h toxav/toxav.c toxav/toxav.h toxav/toxav_hacks.h toxav/toxav_old.c toxav/video.c toxav/video.h) set(toxcore_API_HEADERS ${toxcore_API_HEADERS} ${toxcore_SOURCE_DIR}/toxav/toxav.h^toxav) if(MSVC) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} PkgConfig::OPUS PkgConfig::VPX) else() set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${OPUS_LIBRARIES} ${VPX_LIBRARIES}) set(toxcore_LINK_DIRECTORIES ${toxcore_LINK_DIRECTORIES} ${OPUS_LIBRARY_DIRS} ${VPX_LIBRARY_DIRS}) set(toxcore_INCLUDE_DIRECTORIES ${toxcore_INCLUDE_DIRECTORIES} ${OPUS_INCLUDE_DIRS} ${VPX_INCLUDE_DIRS}) set(toxcore_COMPILE_OPTIONS ${toxcore_COMPILE_OPTIONS} ${OPUS_CFLAGS_OTHER} ${VPX_CFLAGS_OTHER}) endif() set(toxcore_PKGCONFIG_REQUIRES ${toxcore_PKGCONFIG_REQUIRES} opus vpx) endif() ################################################################################ # # :: Block encryption libraries # ################################################################################ set(toxcore_SOURCES ${toxcore_SOURCES} toxencryptsave/toxencryptsave.c toxencryptsave/toxencryptsave.h) set(toxcore_API_HEADERS ${toxcore_API_HEADERS} ${toxcore_SOURCE_DIR}/toxencryptsave/toxencryptsave.h^tox) ################################################################################ # # :: System dependencies # ################################################################################ # These need to come after other dependencies, since e.g. libvpx may depend on # pthread, but doesn't list it in VPX_LIBRARIES. We're adding it here, after # any potential libvpx linking. message("CMAKE_THREAD_LIBS_INIT: ${CMAKE_THREAD_LIBS_INIT}") if(CMAKE_THREAD_LIBS_INIT) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set(toxcore_PKGCONFIG_LIBS ${toxcore_PKGCONFIG_LIBS} ${CMAKE_THREAD_LIBS_INIT}) endif() if(NSL_LIBRARIES) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${NSL_LIBRARIES}) set(toxcore_PKGCONFIG_LIBS ${toxcore_PKGCONFIG_LIBS} -lnsl) endif() if(RT_LIBRARIES) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${RT_LIBRARIES}) set(toxcore_PKGCONFIG_LIBS ${toxcore_PKGCONFIG_LIBS} -lrt) endif() if(SOCKET_LIBRARIES) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${SOCKET_LIBRARIES}) set(toxcore_PKGCONFIG_LIBS ${toxcore_PKGCONFIG_LIBS} -lsocket) endif() if(TARGET PThreads4W::PThreads4W) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} PThreads4W::PThreads4W) elseif(TARGET Threads::Threads) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} Threads::Threads) endif() if(WIN32) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} iphlpapi ws2_32) endif() ################################################################################ # # :: All layers together in one library for ease of use # ################################################################################ # Create combined library from all the sources. if(ENABLE_SHARED) add_library(toxcore_shared SHARED ${toxcore_SOURCES}) set_target_properties(toxcore_shared PROPERTIES OUTPUT_NAME toxcore) target_link_libraries(toxcore_shared PRIVATE ${toxcore_LINK_LIBRARIES}) target_link_directories(toxcore_shared PUBLIC ${toxcore_LINK_DIRECTORIES}) target_include_directories(toxcore_shared SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES}) target_compile_options(toxcore_shared PRIVATE ${toxcore_COMPILE_OPTIONS}) endif() if(ENABLE_STATIC) add_library(toxcore_static STATIC ${toxcore_SOURCES}) if(NOT MSVC) set_target_properties(toxcore_static PROPERTIES OUTPUT_NAME toxcore) endif() target_link_libraries(toxcore_static PRIVATE ${toxcore_LINK_LIBRARIES}) target_link_directories(toxcore_static PUBLIC ${toxcore_LINK_DIRECTORIES}) target_include_directories(toxcore_static SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES}) target_compile_options(toxcore_static PRIVATE ${toxcore_COMPILE_OPTIONS}) endif() if(BUILD_FUZZ_TESTS) add_library(toxcore_fuzz STATIC ${toxcore_SOURCES}) target_link_libraries(toxcore_fuzz PRIVATE ${toxcore_LINK_LIBRARIES}) target_link_directories(toxcore_fuzz PUBLIC ${toxcore_LINK_DIRECTORIES}) target_include_directories(toxcore_fuzz SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES}) target_compile_options(toxcore_fuzz PRIVATE ${toxcore_COMPILE_OPTIONS}) target_compile_definitions(toxcore_fuzz PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") endif() # Make version script (on systems that support it) to limit symbol visibility. make_version_script(toxcore ${toxcore_API_HEADERS}) # Generate pkg-config file, install library to "${CMAKE_INSTALL_LIBDIR}" and install headers to # "${CMAKE_INSTALL_INCLUDEDIR}/tox". install_module(toxcore DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tox) ################################################################################ # # :: Unit tests: no networking, just pure function calls. # ################################################################################ add_library(test_util STATIC toxcore/DHT_test_util.cc toxcore/DHT_test_util.hh toxcore/crypto_core_test_util.cc toxcore/crypto_core_test_util.hh toxcore/mem_test_util.cc toxcore/mem_test_util.hh toxcore/network_test_util.cc toxcore/network_test_util.hh toxcore/test_util.cc toxcore/test_util.hh) function(unit_test subdir target) add_executable(unit_${target}_test ${subdir}/${target}_test.cc) target_link_libraries(unit_${target}_test PRIVATE test_util) if(TARGET toxcore_static) target_link_libraries(unit_${target}_test PRIVATE toxcore_static) else() target_link_libraries(unit_${target}_test PRIVATE toxcore_shared) endif() target_link_libraries(unit_${target}_test PRIVATE GTest::gtest GTest::gtest_main GTest::gmock) set_target_properties(unit_${target}_test PROPERTIES COMPILE_FLAGS "${TEST_CXX_FLAGS}") add_test(NAME ${target} COMMAND ${CROSSCOMPILING_EMULATOR} unit_${target}_test) set_property(TEST ${target} PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw") endfunction() # The actual unit tests follow. # if(UNITTEST AND TARGET GTest::gtest AND TARGET GTest::gmock) unit_test(toxav ring_buffer) unit_test(toxav rtp) unit_test(toxcore DHT) unit_test(toxcore bin_pack) unit_test(toxcore crypto_core) unit_test(toxcore group_announce) unit_test(toxcore group_moderation) unit_test(toxcore list) unit_test(toxcore mem) unit_test(toxcore mono_time) unit_test(toxcore ping_array) unit_test(toxcore test_util) unit_test(toxcore tox) unit_test(toxcore util) endif() add_subdirectory(testing) ################################################################################ # # :: Automated regression tests: create a tox network and run integration tests # ################################################################################ if(AUTOTEST) add_subdirectory(auto_tests) endif() ################################################################################ # # :: Bootstrap daemon # ################################################################################ if(DHT_BOOTSTRAP) add_executable(DHT_bootstrap other/DHT_bootstrap.c other/bootstrap_node_packets.c) if(TARGET toxcore_static) target_link_libraries(DHT_bootstrap PRIVATE toxcore_static) else() target_link_libraries(DHT_bootstrap PRIVATE toxcore_shared) endif() target_link_libraries(DHT_bootstrap PRIVATE misc_tools) if(TARGET unofficial-sodium::sodium) target_link_libraries(DHT_bootstrap PRIVATE unofficial-sodium::sodium) endif() if(TARGET PThreads4W::PThreads4W) target_link_libraries(DHT_bootstrap PRIVATE PThreads4W::PThreads4W) elseif(TARGET Threads::Threads) target_link_libraries(DHT_bootstrap PRIVATE Threads::Threads) endif() install(TARGETS DHT_bootstrap RUNTIME DESTINATION bin) endif() if(BOOTSTRAP_DAEMON) if(LIBCONFIG_FOUND) add_subdirectory(other/bootstrap_daemon) else() message(WARNING "Option BOOTSTRAP_DAEMON is enabled but required library LIBCONFIG was not found.") set(BOOTSTRAP_DAEMON OFF CACHE BOOL "" FORCE) endif() endif() if(BUILD_FUN_UTILS) add_subdirectory(other/fun) endif() if (BUILD_FUZZ_TESTS) add_subdirectory(testing/fuzzing) endif() c-toxcore-0.2.20/CMakePresets.json0000644060175106017510000000127214714247532014722 0ustar robin{ "version": 3, "configurePresets": [ { "name": "windows-default", "binaryDir": "${sourceDir}/_build", "cacheVariables": { "ENABLE_SHARED": true, "ENABLE_STATIC": true, "AUTOTEST": true, "BUILD_MISC_TESTS": true, "BOOTSTRAP_DAEMON": false, "MUST_BUILD_TOXAV": true, "TEST_TIMEOUT_SECONDS": "60", "CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS": true, "CMAKE_COMPILE_WARNING_AS_ERROR": true, "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } } ] } c-toxcore-0.2.20/codecov.yml0000644060175106017510000000071314714247532013645 0ustar robin--- coverage: precision: 2 round: down range: "80...100" status: project: default: # Allow coverage to fluctuate 2% up and down. We can never go below 80% # because of the above range, but toxcore coverage fluctuates a lot due # to low coverage of error paths that sometimes happen. threshold: 2% ignore: - "auto_tests" # ignore tests in coverage analysis - "other" # we don't test the bootstrap daemon c-toxcore-0.2.20/conanfile.py0000644060175106017510000000547414714247532014021 0ustar robin# pylint: disable=not-callable import os import re from conans import CMake from conans import ConanFile from conans.tools import collect_libs from conans.tools import load class ToxConan(ConanFile): name = "c-toxcore" url = "https://tox.chat" description = "The future of online communications." license = "GPL-3.0-only" settings = "os", "compiler", "build_type", "arch" requires = "libsodium/1.0.18", "opus/1.3.1", "libvpx/1.9.0" generators = "cmake_find_package" scm = {"type": "git", "url": "auto", "revision": "auto"} options = { "shared": [True, False], "with_tests": [True, False], } default_options = { "shared": False, "with_tests": False, } _cmake = None def _create_cmake(self): if self._cmake is not None: return self._cmake self._cmake = CMake(self) self._cmake.definitions["AUTOTEST"] = self.options.with_tests self._cmake.definitions["BUILD_MISC_TESTS"] = self.options.with_tests self._cmake.definitions["TEST_TIMEOUT_SECONDS"] = "300" self._cmake.definitions[ "CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS"] = self.options.shared self._cmake.definitions["ENABLE_SHARED"] = self.options.shared self._cmake.definitions["ENABLE_STATIC"] = not self.options.shared self._cmake.definitions["MUST_BUILD_TOXAV"] = True if self.settings.compiler == "Visual Studio": self._cmake.definitions["MSVC_STATIC_SODIUM"] = True self._cmake.definitions[ "FLAT_OUTPUT_STRUCTURE"] = self.options.shared self._cmake.configure() return self._cmake def set_version(self): content = load(os.path.join(self.recipe_folder, "CMakeLists.txt")) version_major = re.search(r"set\(PROJECT_VERSION_MAJOR \"(.*)\"\)", content).group(1) version_minor = re.search(r"set\(PROJECT_VERSION_MINOR \"(.*)\"\)", content).group(1) version_patch = re.search(r"set\(PROJECT_VERSION_PATCH \"(.*)\"\)", content).group(1) self.version = "%s.%s.%s" % ( version_major.strip(), version_minor.strip(), version_patch.strip(), ) def requirements(self): if self.settings.os == "Windows": self.requires("pthreads4w/3.0.0") def build(self): cmake = self._create_cmake() cmake.build() if self.options.with_tests: cmake.test(output_on_failure=True) def package(self): cmake = self._create_cmake() cmake.install() def package_info(self): self.cpp_info.libs = collect_libs(self) if self.settings.os == "Windows": self.cpp_info.system_libs = ["Ws2_32", "Iphlpapi"] c-toxcore-0.2.20/configure.ac0000644060175106017510000003057014714247532013772 0ustar robin# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) AC_INIT([tox], [0.2.20]) AC_CONFIG_AUX_DIR(configure_aux) AC_CONFIG_SRCDIR([toxcore/net_crypto.c]) AM_INIT_AUTOMAKE([foreign 1.10 -Wall -Werror subdir-objects tar-ustar]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_MACRO_DIR([m4]) EXTRA_LT_LDFLAGS= if test "x${prefix}" = "xNONE"; then prefix="${ac_default_prefix}" fi BUILD_DHT_BOOTSTRAP_DAEMON="no" BUILD_DHT_BOOTSTRAP="no" BUILD_TESTS="yes" BUILD_AV="yes" BUILD_TESTING="yes" LIBCONFIG_FOUND="no" SET_SO_VERSION="yes" AC_ARG_ENABLE([soname-versions], [AC_HELP_STRING([--enable-soname-versions], [enable soname versions (must be disabled for android) (default: enabled)]) ], [ if test "x$enableval" = "xno"; then SET_SO_VERSION="no" elif test "x$enableval" = "xyes"; then SET_SO_VERSION="yes" fi ] ) AM_CONDITIONAL(SET_SO_VERSION, test "x$SET_SO_VERSION" = "xyes") AC_ARG_ENABLE([randombytes-stir], [AC_HELP_STRING([--enable-randombytes-stir], [use randombytes_stir() instead of sodium_init() for faster startup on android (default: disabled)]) ], [ if test "x$enableval" = "xyes"; then AC_DEFINE([USE_RANDOMBYTES_STIR], [1], [randombytes_stir() instead of sodium_init()]) fi ] ) AC_ARG_WITH(log-level, AC_HELP_STRING([--with-log-level=LEVEL], [Logger levels: TRACE; DEBUG; INFO; WARNING; ERROR ]), [ if test "x$withval" = "xTRACE"; then AC_DEFINE([MIN_LOGGER_LEVEL], [LOGGER_LEVEL_TRACE], [Logger_Level value]) elif test "x$withval" = "xDEBUG"; then AC_DEFINE([MIN_LOGGER_LEVEL], [LOGGER_LEVEL_DEBUG], [Logger_Level value]) elif test "x$withval" = "xINFO"; then AC_DEFINE([MIN_LOGGER_LEVEL], [LOGGER_LEVEL_INFO], [Logger_Level value]) elif test "x$withval" = "xWARNING"; then AC_DEFINE([MIN_LOGGER_LEVEL], [LOGGER_LEVEL_WARNING], [Logger_Level value]) elif test "x$withval" = "xERROR"; then AC_DEFINE([MIN_LOGGER_LEVEL], [LOGGER_LEVEL_ERROR], [Logger_Level value]) else AC_MSG_WARN([Invalid logger level: $withval. Using default.]) fi ] ) PKG_PROG_PKG_CONFIG AC_ARG_ENABLE([av], [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ], [ if test "x$enableval" = "xno"; then BUILD_AV="no" elif test "x$enableval" = "xyes"; then BUILD_AV="yes" fi ] ) AC_ARG_ENABLE([tests], [AC_HELP_STRING([--disable-tests], [build unit tests (default: auto)]) ], [ if test "x$enableval" = "xno"; then BUILD_TESTS="no" elif test "x$enableval" = "xyes"; then BUILD_TESTS="yes" fi ] ) AC_ARG_ENABLE([daemon], [AC_HELP_STRING([--enable-daemon], [build DHT bootstrap daemon (default: auto)]) ], [ if test "x$enableval" = "xno"; then BUILD_DHT_BOOTSTRAP_DAEMON="no" elif test "x$enableval" = "xyes"; then BUILD_DHT_BOOTSTRAP_DAEMON="yes" fi ] ) AC_ARG_ENABLE([dht-bootstrap], [AC_HELP_STRING([--enable-dht-bootstrap], [build DHT bootstrap utility (default: disabled)]) ], [ if test "x$enableval" = "xno"; then BUILD_DHT_BOOTSTRAP="no" elif test "x$enableval" = "xyes"; then BUILD_DHT_BOOTSTRAP="yes" fi ] ) AC_ARG_ENABLE([rt], [AC_HELP_STRING([--disable-rt], [Disables the librt check (default: auto)]) ], [ if test "x$enableval" = "xno"; then DISABLE_RT="yes" elif test "x$enableval" = "xyes"; then DISABLE_RT="no" fi ] ) AC_ARG_ENABLE([testing], [AC_HELP_STRING([--disable-testing], [build various testing tools (default: auto)]) ], [ if test "x$enableval" = "xno"; then BUILD_TESTING="no" elif test "x$enableval" = "xyes"; then BUILD_TESTING="yes" fi ] ) AC_ARG_ENABLE([[epoll]], [AS_HELP_STRING([[--enable-epoll[=ARG]]], [enable epoll support (yes, no, auto) [auto]])], [enable_epoll=${enableval}], [enable_epoll='auto'] ) AC_ARG_ENABLE([[ipv6]], [AS_HELP_STRING([[--disable-ipv6[=ARG]]], [use ipv4 in tests (yes, no, auto) [auto]])], [use_ipv6=${enableval}], [use_ipv6='auto'] ) if test "$use_ipv6" != "yes"; then AC_DEFINE([USE_IPV6],[0],[define to 0 to force ipv4]) fi AX_HAVE_EPOLL if test "$enable_epoll" != "no"; then if test "${ax_cv_have_epoll}" = "yes"; then AC_DEFINE([TCP_SERVER_USE_EPOLL],[1],[define to 1 to enable epoll support]) enable_epoll='yes' else if test "$enable_epoll" = "yes"; then AC_MSG_ERROR([[Support for epoll was explicitly requested but cannot be enabled on this platform.]]) fi enable_epoll='no' fi fi DEPSEARCH= LIBSODIUM_SEARCH_HEADERS= LIBSODIUM_SEARCH_LIBS= AC_ARG_WITH(dependency-search, AC_HELP_STRING([--with-dependency-search=DIR], [search for dependencies in DIR, i.e., look for libraries in DIR/lib and for headers in DIR/include]), [ DEPSEARCH="$withval" ] ) if test -n "$DEPSEARCH"; then CFLAGS="$CFLAGS -I$DEPSEARCH/include" CPPFLAGS="$CPPFLAGS -I$DEPSEARCH/include" LDFLAGS="$LDFLAGS -L$DEPSEARCH/lib" export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig fi AC_ARG_WITH(libsodium-headers, AC_HELP_STRING([--with-libsodium-headers=DIR], [search for libsodium header files in DIR]), [ LIBSODIUM_SEARCH_HEADERS="$withval" AC_MSG_NOTICE([will search for libsodium header files in $withval]) ] ) AC_ARG_WITH(libsodium-libs, AC_HELP_STRING([--with-libsodium-libs=DIR], [search for libsodium libraries in DIR]), [ LIBSODIUM_SEARCH_LIBS="$withval" AC_MSG_NOTICE([will search for libsodium libraries in $withval]) ] ) # Checks for programs. AC_PROG_CC_C99 if test "x$ac_cv_prog_cc_c99" = "xno" ; then AC_MSG_ERROR([c-toxcore requires a C99 compatible compiler]) fi AM_PROG_CC_C_O m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL WIN32=no MACH=no AC_CANONICAL_HOST case $host_os in *mingw*) WIN32="yes" EXTRA_LT_LDFLAGS="$EXTRA_LT_LDFLAGS -no-undefined" ;; *solaris*) LIBS="$LIBS -lssp -lsocket -lnsl" ;; *qnx*) LIBS="$LIBS -lsocket" ;; *freebsd*|*openbsd*) LDFLAGS="$LDFLAGS -L/usr/local/lib" CFLAGS="$CFLAGS -I/usr/local/include" CPPFLAGS="$CPPFLAGS -I/usr/local/include" ;; darwin*) MACH=yes ;; esac AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") AC_SUBST(EXTRA_LT_LDFLAGS) # Needed math flags for some compilers MATH_LDFLAGS="-lm" AC_SUBST(MATH_LDFLAGS) # Checks for libraries. AC_CHECK_FUNCS([explicit_bzero memset_s]) PKG_CHECK_MODULES([LIBSODIUM], [libsodium], [ LIBSODIUM_FOUND="yes" ], [ LIBSODIUM_FOUND="no" ]) if test "x$LIBSODIUM_FOUND" = "xno"; then LIBSODIUM_LIBS= LIBSODIUM_LDFLAGS= LDFLAGS_SAVE="$LDFLAGS" if test -n "$LIBSODIUM_SEARCH_LIBS"; then LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS $LDFLAGS" AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256, [ LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS" LIBSODIUM_LIBS="-lsodium" ], [ AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS or library version is too old]) ] ) else AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256, [], [ AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/ or library version is too old]) ] ) fi LDFLAGS="$LDFLAGS_SAVE" AC_SUBST(LIBSODIUM_LIBS) AC_SUBST(LIBSODIUM_LDFLAGS) fi # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) if test "x$LIBSODIUM_FOUND" = "xno"; then LIBSODIUM_CFLAGS= CFLAGS_SAVE="$CFLAGS" CPPFLAGS_SAVE="$CPPFLAGS" if test -n "$LIBSODIUM_SEARCH_HEADERS"; then CFLAGS="-I$LIBSODIUM_SEARCH_HEADERS $CFLAGS" CPPFLAGS="-I$LIBSODIUM_SEARCH_HEADERS $CPPFLAGS" AC_CHECK_HEADER(sodium.h, [ LIBSODIUM_CFLAGS="-I$LIBSODIUM_SEARCH_HEADERS" ], [ AC_MSG_ERROR([header files for required library libsodium were not found in requested location $LIBSODIUM_SEARCH_HEADERS]) ] ) else AC_CHECK_HEADER(sodium.h, [], [ AC_MSG_ERROR([header files for required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/]) ] ) fi CFLAGS="$CFLAGS_SAVE" CPPFLAGS="$CPPFLAGS_SAVE" AC_SUBST(LIBSODIUM_CFLAGS) fi # Checks for library functions. if (test "x$WIN32" != "xyes") && (test "x$MACH" != "xyes") && (test "x${host_os#*openbsd}" = "x$host_os") && (test "x$DISABLE_RT" != "xyes"); then AC_CHECK_LIB(rt, clock_gettime, [ RT_LIBS="-lrt" AC_SUBST(RT_LIBS) ], [ AC_MSG_ERROR([required library rt was not found on your system]) ] ) fi AX_PTHREAD( [], [ AC_MSG_ERROR([required library pthread was not found on your system]) ] ) AC_CHECK_LIB([pthread], [pthread_self], [ PTHREAD_LDFLAGS="-lpthread" AC_SUBST(PTHREAD_LDFLAGS) ] ) if test "x$BUILD_AV" = "xyes"; then PKG_CHECK_MODULES([OPUS], [opus], [], [ AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS]) BUILD_AV="no" ] ) fi if test "x$BUILD_AV" = "xyes"; then PKG_CHECK_MODULES([VPX], [vpx], [], [ AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS]) BUILD_AV="no" ] ) fi if test "x$BUILD_AV" = "xyes"; then # toxcore lib needs an global? # So far this works okay AV_LIBS="$OPUS_LIBS $VPX_LIBS" AC_SUBST(AV_LIBS) AV_CFLAGS="$OPUS_CFLAGS $VPX_CFLAGS" AC_SUBST(AV_CFLAGS) fi if test -n "$PKG_CONFIG"; then if test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes"; then PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.4.6], [ LIBCONFIG_FOUND="yes" ], [ AC_MSG_WARN([$LIBCONFIG_PKG_ERRORS]) AC_MSG_WARN([libconfig not available, will not build DHT bootstrap daemon]) BUILD_DHT_BOOTSTRAP_DAEMON="no" ]) fi else AC_MSG_WARN([pkg-config was not found on your system, will search for libraries manually]) fi if (test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes") && \ (test "x$LIBCONFIG_FOUND" = "xno"); then AC_CHECK_HEADER(libconfig.h, [], [ AC_MSG_WARN([header files for library libconfig was not found on your system, not building DHT bootstrap daemon]) BUILD_DHT_BOOTSTRAP_DAEMON="no" ] ) if test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes"; then AC_CHECK_LIB(config, config_read, [], [ AC_MSG_WARN([library libconfig was not found on the system]) BUILD_DHT_BOOTSTRAP_DAEMON="no" ] ) fi fi if test "x$WIN32" = "xyes"; then AC_CHECK_LIB(ws2_32, main, [ WINSOCK2_LIBS="-liphlpapi -lws2_32" AC_SUBST(WINSOCK2_LIBS) ], [ AC_MSG_ERROR([required library was not found on the system, please check your MinGW installation]) ] ) fi AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = "xyes") AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP, test "x$BUILD_DHT_BOOTSTRAP" = "xyes") AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") AC_CONFIG_FILES([Makefile build/Makefile libtoxcore.pc tox.spec ]) AM_COND_IF(BUILD_AV, [ AC_CONFIG_FILES([libtoxav.pc]) ],) AC_OUTPUT c-toxcore-0.2.20/docs/0000755060175106017510000000000014714247532012427 5ustar robinc-toxcore-0.2.20/docs/av_api.md0000644060175106017510000001624214714247532014215 0ustar robin# A/V API reference ## Take toxmsi/phone.c as a reference ### Initialization: ``` phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port); ``` function initializes sample phone. `_listen_port` and `_send_port` are variables only meant for local testing. You will not have to do anything regarding to that since everything will be started within a messenger. Phone requires one msi session and two rtp sessions (one for audio and one for video). ``` msi_session_t* msi_init_session( void* _core_handler, const uint8_t* _user_agent ); ``` initializes msi session. Params: ``` void* _core_handler - pointer to an object handling networking, const uint8_t* _user_agent - string describing phone client version. ``` Return value: `msi_session_t*` - pointer to a newly created msi session handler. ### `msi_session_t` reference: How to handle msi session: Controlling is done via callbacks and action handlers. First register callbacks for every state/action received and make sure NOT TO PLACE SOMETHING LIKE LOOPS THAT TAKES A LOT OF TIME TO EXECUTE; every callback is being called directly from event loop. You can find examples in phone.c. Register callbacks: ``` void msi_register_callback_call_started ( MCALLBACK ); void msi_register_callback_call_canceled ( MCALLBACK ); void msi_register_callback_call_rejected ( MCALLBACK ); void msi_register_callback_call_ended ( MCALLBACK ); void msi_register_callback_recv_invite ( MCALLBACK ); void msi_register_callback_recv_ringing ( MCALLBACK ); void msi_register_callback_recv_starting ( MCALLBACK ); void msi_register_callback_recv_ending ( MCALLBACK ); void msi_register_callback_recv_error ( MCALLBACK ); void msi_register_callback_requ_timeout ( MCALLBACK ); ``` MCALLBACK is defined as: `void (*callback) (void* _arg)` `msi_session_t*` handler is being thrown as `_arg` so you can use that and `_agent_handler` to get to your own phone handler directly from callback. Actions: ``` int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms ); ``` Sends call invite. Before calling/sending invite `msi_session_t::_friend_id` is needed to be set or else it will not work. `_call_type` is type of the call ( Audio/Video ) and `_timeoutms` is how long will poll wait until request is terminated. ``` int msi_hangup ( msi_session_t* _session ); ``` Hangs up active call ``` int msi_answer ( msi_session_t* _session, call_type _call_type ); ``` Answer incoming call. `_call_type` set's callee call type. ``` int msi_cancel ( msi_session_t* _session ); ``` Cancel current request. ``` int msi_reject ( msi_session_t* _session ); ``` Reject incoming call. ### Now for rtp: You will need 2 sessions; one for audio one for video. You start them with: ``` rtp_session_t* rtp_init_session ( int _max_users, int _multi_session ); ``` Params: ``` int _max_users - max users. -1 if undefined int _multi_session - any positive number means uses multi session; -1 if not. ``` Return value: ``` rtp_session_t* - pointer to a newly created rtp session handler. ``` ### How to handle rtp session: Take a look at ``` void* phone_handle_media_transport_poll ( void* _hmtc_args_p ) in phone.c ``` on example. Basically what you do is just receive a message via: ``` struct rtp_msg_s* rtp_recv_msg ( rtp_session_t* _session ); ``` and then you use payload within the `rtp_msg_s` struct. Don't forget to deallocate it with: `void rtp_free_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg );` Receiving should be thread safe so don't worry about that. When you capture and encode a payload you want to send it ( obviously ). first create a new message with: ``` struct rtp_msg_s* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length ); ``` and then send it with: ``` int rtp_send_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg, void* _core_handler ); ``` `_core_handler` is the same network handler as in `msi_session_s` struct. ## A/V initialization: ``` int init_receive_audio(codec_state *cs); int init_receive_video(codec_state *cs); Initialises the A/V decoders. On failure it will print the reason and return 0. On success it will return 1. int init_send_audio(codec_state *cs); int init_send_video(codec_state *cs); Initialises the A/V encoders. On failure it will print the reason and return 0. On success it will return 1. init_send_audio will also let the user select an input device. init_send_video will determine the webcam's output codec and initialise the appropriate decoder. int video_encoder_refresh(codec_state *cs, int bps); Reinitialises the video encoder with a new bitrate. ffmpeg does not expose the needed VP8 feature to change the bitrate on the fly, so this serves as a workaround. In the future, VP8 should be used directly and ffmpeg should be dropped from the dependencies. The variable bps is the required bitrate in bits per second. ``` ### A/V encoding/decoding: ``` void *encode_video_thread(void *arg); ``` Spawns the video encoding thread. The argument should hold a pointer to a `codec_state`. This function should only be called if video encoding is supported (when `init_send_video` returns 1). Each video frame gets encoded into a packet, which is sent via RTP. Every 60 frames a new bidirectional interframe is encoded. ``` void *encode_audio_thread(void *arg); ``` Spawns the audio encoding thread. The argument should hold a pointer to a `codec_state`. This function should only be called if audio encoding is supported (when `init_send_audio` returns 1). Audio frames are read from the selected audio capture device during initialisation. This audio capturing can be rerouted to a different device on the fly. Each audio frame is encoded into a packet, and sent via RTP. All audio frames have the same amount of samples, which is defined in `AV_codec.h`. ``` int video_decoder_refresh(codec_state *cs, int width, int height); ``` Sets the SDL window dimensions and creates a pixel buffer with the requested size. It also creates a scaling context, which will be used to convert the input image format to YUV420P. ``` void *decode_video_thread(void *arg); ``` Spawns a video decoding thread. The argument should hold a pointer to a `codec_state`. The `codec_state` is assumed to contain a successfully initialised video decoder. This function reads video packets and feeds them to the video decoder. If the video frame's resolution has changed, `video_decoder_refresh()` is called. Afterwards, the frame is displayed on the SDL window. ``` void *decode_audio_thread(void *arg); ``` Spawns an audio decoding thread. The argument should hold a pointer to a `codec_state`. The `codec_state` is assumed to contain a successfully initialised audio decoder. All received audio packets are pushed into a jitter buffer and are reordered. If there is a missing packet, or a packet has arrived too late, it is treated as a lost packet and the audio decoder is informed of the packet loss. The audio decoder will then try to reconstruct the lost packet, based on information from previous packets. Audio is played on the default OpenAL output device. If you have any more qustions/bug reports/feature request contact the following users on the irc channel #tox-dev on irc.freenode.net: For RTP and MSI: mannol For audio and video: Martijnvdc c-toxcore-0.2.20/docs/Doxyfile0000644060175106017510000033703614714247532014151 0ustar robin# Doxyfile 1.9.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "Tox Protocol Reference Implementation" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "The future of online communications" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = _docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # By default Python docstrings are displayed as preformatted text and doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the # doxygen's special commands can be used and the contents of the docstring # documentation blocks is shown as doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". Note that you cannot put \n's in the value part of an alias # to insert newlines (in the resulting output). You can put ^^ in the value part # of an alias to insert a newline as if a physical newline was in the original # file. When you need a literal { or } or , in the value part of an alias you # have to escape them by means of a backslash (\), this can lead to conflicts # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 # The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, # which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If this flag is set to YES, the name of an unnamed parameter in a declaration # will be determined by the corresponding definition. By default unnamed # parameters remain unnamed in the output. # The default value is: YES. RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that # are not case sensitive the option should be be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. # The default value is: YES. SHOW_HEADERFILE = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = NO # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete # function parameter documentation. If set to NO, doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. WARN_IF_INCOMPLETE_DOC = NO # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = toxav toxcore toxencryptsave # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.l \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f18 \ *.f \ *.for \ *.vhd \ *.vhdl \ *.ucf \ *.qsf \ *.ice # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = doxygen-awesome-css/doxygen-awesome.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To # create a documentation set, doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with # a.o. the download links, offline the HTML help workshop was already many years # in maintenance mode). You can download the HTML help workshop from the web # archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an # example, the default style sheet generated by doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the # project logo, title, and description. If either GENERATOR_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. # Possible values are: png (the default) and svg (looks nicer but requires the # pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with # regards to the different settings, so it is possible that also other MathJax # settings have to be changed when switching between the different MathJax # versions. # Possible values are: MathJax_2 and MathJax_3. # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_VERSION = MathJax_2 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax # version 2 (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 # (see: # http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported # for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. The default value is: # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # for MathJax version 2 (see # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /