diff --git a/.circleci/cmake-tsan b/.circleci/cmake-tsan index ab98e0de53..9fabb5ab97 100755 --- a/.circleci/cmake-tsan +++ b/.circleci/cmake-tsan @@ -22,6 +22,7 @@ cmake -B_build -H. -GNinja \ -DSTRICT_ABI=ON \ -DTEST_TIMEOUT_SECONDS=120 \ -DUSE_IPV6=OFF \ + -DUSE_LIBEV=ON \ -DAUTOTEST=ON cd _build diff --git a/.circleci/config.yml b/.circleci/config.yml index 9fd1c82266..2770f40b12 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,20 +3,14 @@ version: 2 workflows: version: 2 - program-analysis: + circleci: 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 + - cimplefmt + - generate-events jobs: bazel-asan: @@ -29,31 +23,7 @@ jobs: - 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: + static-analysis: working_directory: ~/work docker: - image: ubuntu @@ -62,12 +32,14 @@ jobs: - run: &apt_install apt-get update && DEBIAN_FRONTEND=noninteractive - apt-get install -y --no-install-recommends + apt-get install -y ca-certificates clang cmake git + libbenchmark-dev libconfig-dev + libev-dev libgmock-dev libgtest-dev libopus-dev @@ -76,39 +48,6 @@ jobs: 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 @@ -120,6 +59,8 @@ jobs: - run: other/analysis/check_logger_levels - run: other/analysis/run-clang - run: other/analysis/run-gcc + - run: other/analysis/run-cppcheck + - run: other/analysis/run-clang-analyze clang-analyze: working_directory: ~/work @@ -141,9 +82,26 @@ jobs: - run: *apt_install - run: apt-get install -y --no-install-recommends - ca-certificates - python3-pip + cpplint - checkout - run: git submodule update --init --recursive - - run: pip install cpplint - run: other/analysis/run-cpplint + + cimplefmt: + working_directory: ~/work + machine: { image: ubuntu-2204:current } + + steps: + - checkout + - run: git submodule update --init --recursive + - run: other/docker/cimplefmt/run -u $(find tox* -name "*.[ch]") + + generate-events: + working_directory: ~/work + machine: { image: ubuntu-2204:current } + + steps: + - checkout + - run: git submodule update --init --recursive + - run: other/event_tooling/run + - run: git diff --exit-code diff --git a/.cirrus.yml b/.cirrus.yml index bb477b26ef..cc309170c8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,6 @@ --- bazel-opt_task: + timeout_in: 5m container: image: toxchat/toktok-stack:latest-release cpu: 2 @@ -8,14 +9,17 @@ bazel-opt_task: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - - cd /src/workspace && bazel test -k + - cd /src/workspace && bazel + --max_idle_secs=5 + test -k --build_tag_filters=-haskell --test_tag_filters=-haskell -- //c-toxcore/... - -//c-toxcore/auto_tests:tcp_relay_test # TODO(robinlinden): Why does this pass locally but not in Cirrus? + -//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 @@ -24,15 +28,35 @@ bazel-dbg_task: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - - cd /src/workspace && bazel test -k + - cd /src/workspace && bazel + --max_idle_secs=5 + test -k + --remote_cache=http://$CIRRUS_HTTP_CACHE_HOST --build_tag_filters=-haskell --test_tag_filters=-haskell - --remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST -- //c-toxcore/... - -//c-toxcore/auto_tests:tcp_relay_test # TODO(robinlinden): Why does this pass locally but not in Cirrus? + -//c-toxcore/auto_tests:tcp_relay_test # Cirrus doesn't allow external network connections. + +bazel-msan_task: + timeout_in: 5m + container: + image: toxchat/toktok-stack:latest-msan + 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 + --max_idle_secs=5 + test -k + --remote_cache=http://$CIRRUS_HTTP_CACHE_HOST + -- + //c-toxcore/auto_tests:lossless_packet_test cimple_task: + timeout_in: 5m container: image: toxchat/toktok-stack:latest-release cpu: 2 @@ -41,15 +65,18 @@ cimple_task: - git submodule update --init --recursive - /src/workspace/tools/inject-repo c-toxcore test_all_script: - - cd /src/workspace && bazel test -k + - cd /src/workspace && bazel + --max_idle_secs=5 + test -k --build_tag_filters=haskell --test_tag_filters=haskell -- //c-toxcore/... freebsd_task: + timeout_in: 5m freebsd_instance: - image_family: freebsd-14-0 + image_family: freebsd-14-1 configure_script: - PAGER=cat ASSUME_ALWAYS_YES=YES pkg install cmake @@ -69,7 +96,7 @@ freebsd_task: cmake . \ -DMIN_LOGGER_LEVEL=TRACE \ -DMUST_BUILD_TOXAV=ON \ - -DNON_HERMETIC_TESTS=ON \ + -DNON_HERMETIC_TESTS=OFF \ -DTEST_TIMEOUT_SECONDS=50 \ -DUSE_IPV6=OFF \ -DAUTOTEST=ON diff --git a/.github/scripts/cmake-android b/.github/scripts/cmake-android index d15f555c79..95ec6600a8 100755 --- a/.github/scripts/cmake-android +++ b/.github/scripts/cmake-android @@ -10,7 +10,7 @@ ABI=${1:-"armeabi-v7a"} case $ABI in armeabi-v7a) TARGET=armv7a-linux-androideabi - NDK_API=19 + NDK_API=21 ;; arm64-v8a) TARGET=aarch64-linux-android @@ -18,7 +18,7 @@ case $ABI in ;; x86) TARGET=i686-linux-android - NDK_API=19 + NDK_API=21 ;; x86_64) TARGET=x86_64-linux-android diff --git a/.github/scripts/flags-clang.sh b/.github/scripts/flags-clang.sh index f5ae253fbc..f0d9a11c87 100644 --- a/.github/scripts/flags-clang.sh +++ b/.github/scripts/flags-clang.sh @@ -36,15 +36,17 @@ 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 -# TODO(iphydf): Clean these up. They are likely not bugs, but still -# potential issues and probably confusing. -add_flag -Wno-sign-compare +# 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 diff --git a/.github/scripts/flags-gcc.sh b/.github/scripts/flags-gcc.sh index 0cacdb4b17..50a0531ac9 100644 --- a/.github/scripts/flags-gcc.sh +++ b/.github/scripts/flags-gcc.sh @@ -47,8 +47,7 @@ add_flag -Wunused-value # struct Foo foo = {0}; is a common idiom. add_flag -Wno-missing-field-initializers -# TODO(iphydf): Clean these up. They are likely not bugs, but still -# potential issues and probably confusing. +# 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 diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000000..f618b9ecbf --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,12 @@ +name: checks + +on: + pull_request: + branches: [master] + types: [opened, reopened, synchronize, milestoned] + pull_request_target: + branches: [master] + +jobs: + checks: + uses: TokTok/ci-tools/.github/workflows/check-release.yml@master diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7988ea26b1..99cbe7b2d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: 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 + runs-on: ubuntu-22.04 steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -34,37 +34,34 @@ jobs: with: file: other/docker/${{ matrix.tool }}/${{ matrix.tool }}.Dockerfile - coverage-linux: - runs-on: ubuntu-latest + sanitizer: + strategy: + fail-fast: false + matrix: + sanitizer: [asan, tsan, ubsan] + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 with: - submodules: recursive - - name: Build, test, and upload coverage - run: other/docker/coverage/run - - generate-events: - runs-on: ubuntu-latest - steps: + driver: docker - uses: actions/checkout@v4 with: submodules: recursive - - name: Run generate_event_c - run: | - other/event_tooling/run - git diff --exit-code + - name: Run sanitizer + run: other/docker/circleci/run "${{ matrix.sanitizer }}" - cimplefmt: - runs-on: ubuntu-latest + coverage-linux: + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: submodules: recursive - - name: Run cimplefmt - run: other/docker/cimplefmt/run -u $(find tox* -name "*.[ch]") + - name: Build, test, and upload coverage + run: other/docker/coverage/run build-android: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: @@ -96,7 +93,7 @@ jobs: with: submodules: recursive - name: Export GitHub Actions cache environment variables - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); @@ -111,7 +108,7 @@ jobs: ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 --build-config Debug build-netbsd: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: @@ -146,7 +143,7 @@ jobs: ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 build-freebsd: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: @@ -183,7 +180,7 @@ jobs: ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6 mypy: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..9f4ee30be3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,12 @@ +name: 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 diff --git a/.gitmodules b/.gitmodules index e2793dd7e9..5f564571dc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "third_party/cmp"] path = third_party/cmp - url = https://github.com/camgunz/cmp + url = https://github.com/TokTok/cmp diff --git a/BUILD.bazel b/BUILD.bazel index db5f5693df..481b46ae39 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -8,18 +8,24 @@ genrule( srcs = [ "//c-toxcore/toxav:toxav.h", "//c-toxcore/toxcore:tox.h", + "//c-toxcore/toxcore:tox_dispatch.h", + "//c-toxcore/toxcore:tox_events.h", "//c-toxcore/toxcore:tox_private.h", "//c-toxcore/toxencryptsave:toxencryptsave.h", ], outs = [ "tox/toxav.h", "tox/tox.h", + "tox/tox_dispatch.h", + "tox/tox_events.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_dispatch.h) $(GENDIR)/c-toxcore/tox/tox_dispatch.h + cp $(location //c-toxcore/toxcore:tox_events.h) $(GENDIR)/c-toxcore/tox/tox_events.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 """, diff --git a/CHANGELOG.md b/CHANGELOG.md index 082b788c4a..36bfb39b2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,306 @@ +## 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. @@ -107,6 +404,7 @@ ### 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d779fa076..abe79dc626 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ set_source_files_properties( # versions in a synchronised way. set(PROJECT_VERSION_MAJOR "0") set(PROJECT_VERSION_MINOR "2") -set(PROJECT_VERSION_PATCH "18") +set(PROJECT_VERSION_PATCH "20") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") # set .so library version / following libtool scheme @@ -146,6 +146,8 @@ 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) @@ -159,7 +161,7 @@ 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) + set(BOOTSTRAP_DAEMON OFF CACHE BOOL "" FORCE) endif() option(BUILD_FUZZ_TESTS "Build fuzzing harnesses" OFF) @@ -175,6 +177,7 @@ 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() @@ -182,11 +185,11 @@ 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) + 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) + set(BUILD_TOXAV OFF CACHE BOOL "" FORCE) endif() endif() @@ -194,6 +197,12 @@ endif() # We don't transfer floats over the network, so we disable this functionality. add_definitions(-DCMP_NO_FLOAT=1) +# TODO(iphydf): Check whether this is actually true. +option(USE_LIBEV "Whether to use libev for tox_loop" OFF) +if(USE_LIBEV) + add_definitions(-DHAVE_LIBEV=1) +endif() + ################################################################################ # # :: Tox Core Library @@ -320,6 +329,8 @@ set(toxcore_SOURCES toxcore/ping.h toxcore/shared_key_cache.c toxcore/shared_key_cache.h + toxcore/sort.c + toxcore/sort.h toxcore/state.c toxcore/state.h toxcore/TCP_client.c @@ -349,7 +360,9 @@ set(toxcore_SOURCES toxcore/tox_unpack.h toxcore/util.c toxcore/util.h) -if(TARGET unofficial-sodium::sodium) +if(TARGET libsodium::libsodium) + set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} libsodium::libsodium) +elseif(TARGET unofficial-sodium::sodium) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} unofficial-sodium::sodium) else() set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${LIBSODIUM_LIBRARIES}) @@ -389,13 +402,16 @@ if(BUILD_TOXAV) 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) + if(TARGET Opus::opus AND TARGET libvpx::libvpx) + set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} Opus::opus libvpx::libvpx) + elseif(TARGET PkgConfig::OPUS AND TARGET PkgConfig::VPX) set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} PkgConfig::OPUS PkgConfig::VPX) else() set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} ${OPUS_LIBRARIES} ${VPX_LIBRARIES}) @@ -448,7 +464,9 @@ if(SOCKET_LIBRARIES) set(toxcore_PKGCONFIG_LIBS ${toxcore_PKGCONFIG_LIBS} -lsocket) endif() -if(TARGET PThreads4W::PThreads4W) +if(TARGET pthreads4w::pthreads4w) + set(toxcore_LINK_LIBRARIES ${toxcore_LINK_LIBRARIES} pthreads4w::pthreads4w) +elseif(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) @@ -506,17 +524,19 @@ install_module(toxcore DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tox) # ################################################################################ -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) +if(UNITTEST) + 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) +endif() function(unit_test subdir target) add_executable(unit_${target}_test ${subdir}/${target}_test.cc) @@ -526,6 +546,13 @@ function(unit_test subdir target) else() target_link_libraries(unit_${target}_test PRIVATE toxcore_shared) endif() + if(TARGET pthreads4w::pthreads4w) + target_link_libraries(unit_${target}_test PRIVATE pthreads4w::pthreads4w) + elseif(TARGET PThreads4W::PThreads4W) + target_link_libraries(unit_${target}_test PRIVATE PThreads4W::PThreads4W) + elseif(TARGET Threads::Threads) + target_link_libraries(unit_${target}_test PRIVATE Threads::Threads) + 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) @@ -534,7 +561,7 @@ endfunction() # The actual unit tests follow. # -if(TARGET GTest::gtest AND TARGET GTest::gmock) +if(UNITTEST AND TARGET GTest::gtest AND TARGET GTest::gmock) unit_test(toxav ring_buffer) unit_test(toxav rtp) unit_test(toxcore DHT) @@ -579,10 +606,14 @@ if(DHT_BOOTSTRAP) target_link_libraries(DHT_bootstrap PRIVATE toxcore_shared) endif() target_link_libraries(DHT_bootstrap PRIVATE misc_tools) - if(TARGET unofficial-sodium::sodium) + if(TARGET libsodium::libsodium) + target_link_libraries(DHT_bootstrap PRIVATE libsodium::libsodium) + elseif(TARGET unofficial-sodium::sodium) target_link_libraries(DHT_bootstrap PRIVATE unofficial-sodium::sodium) endif() - if(TARGET PThreads4W::PThreads4W) + if(TARGET pthreads4w::pthreads4w) + target_link_libraries(DHT_bootstrap PRIVATE pthreads4w::pthreads4w) + elseif(TARGET PThreads4W::PThreads4W) target_link_libraries(DHT_bootstrap PRIVATE PThreads4W::PThreads4W) elseif(TARGET Threads::Threads) target_link_libraries(DHT_bootstrap PRIVATE Threads::Threads) @@ -595,7 +626,7 @@ if(BOOTSTRAP_DAEMON) add_subdirectory(other/bootstrap_daemon) else() message(WARNING "Option BOOTSTRAP_DAEMON is enabled but required library LIBCONFIG was not found.") - set(BOOTSTRAP_DAEMON OFF) + set(BOOTSTRAP_DAEMON OFF CACHE BOOL "" FORCE) endif() endif() diff --git a/CMakePresets.json b/CMakePresets.json index 45caa10d58..2a8ebf9175 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,6 +7,7 @@ "cacheVariables": { "ENABLE_SHARED": true, "ENABLE_STATIC": true, + "FLAT_OUTPUT_STRUCTURE": true, "AUTOTEST": true, "BUILD_MISC_TESTS": true, "BOOTSTRAP_DAEMON": false, @@ -17,5 +18,19 @@ "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } } + ], + "buildPresets": [ + { + "name": "windows-default", + "configurePreset": "windows-default", + "description": "Build for Windows using default settings" + } + ], + "testPresets": [ + { + "name": "windows-default", + "configurePreset": "windows-default", + "description": "Run tests for Windows using default settings" + } ] } diff --git a/INSTALL.md b/INSTALL.md index 3754faac3b..67e8371721 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -151,6 +151,7 @@ There are some options that are available to configure the build. | `PROXY_TEST` | Enable proxy test (requires `other/proxy/proxy_server.go` to be running). | ON or OFF | OFF | | `STRICT_ABI` | Enforce strict ABI export in dynamic libraries. | ON or OFF | OFF | | `TEST_TIMEOUT_SECONDS` | Limit runtime of each test to the number of seconds specified. | Positive number or nothing (empty string). | Empty string. | +| `UNITTEST` | Enable unit tests (disable if you don't have a working gmock or gtest). | ON or OFF | ON | | `USE_IPV6` | Use IPv6 in tests. | ON or OFF | ON | You can get this list of option using the following commands diff --git a/auto_tests/BUILD.bazel b/auto_tests/BUILD.bazel index 17606cafe5..24a3addbe0 100644 --- a/auto_tests/BUILD.bazel +++ b/auto_tests/BUILD.bazel @@ -78,6 +78,7 @@ extra_data = { "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", + "//c-toxcore/toxcore:tox_unpack", "//c-toxcore/toxcore:util", "//c-toxcore/toxencryptsave", "@libsodium", diff --git a/auto_tests/CMakeLists.txt b/auto_tests/CMakeLists.txt index d891ba122b..5dae941359 100644 --- a/auto_tests/CMakeLists.txt +++ b/auto_tests/CMakeLists.txt @@ -9,7 +9,9 @@ if(TARGET toxcore_static) else() target_link_libraries(auto_test_support PRIVATE toxcore_shared) endif() -if(TARGET PThreads4W::PThreads4W) +if(TARGET pthreads4w::pthreads4w) + target_link_libraries(auto_test_support PRIVATE pthreads4w::pthreads4w) +elseif(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) @@ -23,7 +25,9 @@ function(auto_test target) else() target_link_libraries(auto_${target}_test PRIVATE toxcore_shared) endif() - if(TARGET PThreads4W::PThreads4W) + if(TARGET pthreads4w::pthreads4w) + target_link_libraries(auto_${target}_test PRIVATE pthreads4w::pthreads4w) + elseif(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) @@ -79,6 +83,7 @@ auto_test(set_name) auto_test(set_status_message) auto_test(tox_dispatch) auto_test(tox_events) +auto_test(tox_loop) auto_test(tox_many) auto_test(tox_many_tcp) auto_test(tox_strncasecmp) @@ -98,7 +103,10 @@ if(BUILD_TOXAV) auto_test(toxav_basic) auto_test(toxav_many) - if(MSVC) + if(TARGET libvpx::libvpx) + target_link_libraries(auto_toxav_basic_test PRIVATE libvpx::libvpx) + target_link_libraries(auto_toxav_many_test PRIVATE libvpx::libvpx) + elseif(TARGET PkgConfig::VPX) target_link_libraries(auto_toxav_basic_test PRIVATE PkgConfig::VPX) target_link_libraries(auto_toxav_many_test PRIVATE PkgConfig::VPX) else() diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c index 45309d0941..b59fa9469b 100644 --- a/auto_tests/TCP_test.c +++ b/auto_tests/TCP_test.c @@ -53,7 +53,7 @@ static void test_basic(void) ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); logger_callback_log(logger, print_debug_logger, nullptr, nullptr); // Attempt to create a new TCP_Server instance. @@ -74,7 +74,7 @@ static void test_basic(void) 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); + bool ret = net_connect(ns, 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. @@ -102,7 +102,7 @@ static void test_basic(void) 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, + int ret = encrypt_data(mem, 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."); @@ -128,7 +128,7 @@ static void test_basic(void) 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, + ret = decrypt_data(mem, 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]; @@ -143,7 +143,7 @@ static void test_basic(void) 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); + encrypt_data_symmetric(mem, 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); @@ -174,7 +174,7 @@ static void test_basic(void) "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); + ret = decrypt_data_symmetric(mem, 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); @@ -213,7 +213,7 @@ static struct sec_TCP_con *new_tcp_con(const Logger *logger, const Memory *mem, localhost.ip = get_loopback(); localhost.port = net_htons(ports[random_u32(rng) % NUM_PORTS]); - bool ok = net_connect(mem, logger, sock, &localhost); + bool ok = net_connect(ns, 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]; @@ -228,7 +228,7 @@ static struct sec_TCP_con *new_tcp_con(const Logger *logger, const Memory *mem, 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, + int ret = encrypt_data(mem, 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."); @@ -248,7 +248,7 @@ static struct sec_TCP_con *new_tcp_con(const Logger *logger, const Memory *mem, 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, + ret = decrypt_data(mem, 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); @@ -271,7 +271,7 @@ static int write_packet_tcp_test_connection(const Logger *logger, struct sec_TCP 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)); + int len = encrypt_data_symmetric(con->mem, con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (packet_size - sizeof(uint16_t))) { return -1; @@ -296,7 +296,7 @@ static int read_packet_sec_tcp(const Logger *logger, struct sec_TCP_con *con, ui 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); + rlen = decrypt_data_symmetric(con->mem, 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; @@ -312,7 +312,7 @@ static void test_some(void) ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; @@ -506,7 +506,7 @@ static void test_client(void) const Memory *mem = os_memory(); ck_assert(mem != nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; @@ -525,8 +525,9 @@ static void test_client(void) 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); - do_tcp_connection(logger, mono_time, conn, 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. @@ -560,6 +561,7 @@ static void test_client(void) 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); @@ -641,7 +643,7 @@ static void test_client_invalid(void) ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; @@ -719,7 +721,7 @@ static void test_tcp_connection(void) ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); tcp_data_callback_called = 0; uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; @@ -832,7 +834,7 @@ static void test_tcp_connection2(void) ck_assert(mem != nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); - Logger *logger = logger_new(); + Logger *logger = logger_new(mem); tcp_oobdata_callback_called = 0; tcp_data_callback_called = 0; diff --git a/auto_tests/announce_test.c b/auto_tests/announce_test.c index c4f080de4e..ef93095b1b 100644 --- a/auto_tests/announce_test.c +++ b/auto_tests/announce_test.c @@ -57,7 +57,7 @@ static void test_store_data(void) const Memory *mem = os_memory(); ck_assert(mem != nullptr); - Logger *log = logger_new(); + Logger *log = logger_new(mem); ck_assert(log != nullptr); logger_callback_log(log, print_debug_logger, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); diff --git a/auto_tests/conference_av_test.c b/auto_tests/conference_av_test.c index 39383bd74c..28a2a3a1e3 100644 --- a/auto_tests/conference_av_test.c +++ b/auto_tests/conference_av_test.c @@ -420,7 +420,7 @@ static void test_groupav(AutoTox *autotoxes) 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]) != UINT32_MAX, + 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"); diff --git a/auto_tests/conference_double_invite_test.c b/auto_tests/conference_double_invite_test.c index 06d880a20d..4d16c8158b 100644 --- a/auto_tests/conference_double_invite_test.c +++ b/auto_tests/conference_double_invite_test.c @@ -28,7 +28,7 @@ static void handle_conference_invite( ck_assert_msg(!state->joined, "invitation callback generated for already joined conference"); - if (friend_number != -1) { + 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, diff --git a/auto_tests/conference_invite_merge_test.c b/auto_tests/conference_invite_merge_test.c index d0af332d22..536f47fd74 100644 --- a/auto_tests/conference_invite_merge_test.c +++ b/auto_tests/conference_invite_merge_test.c @@ -21,7 +21,7 @@ static void handle_conference_invite( 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 != -1) { + 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, diff --git a/auto_tests/crypto_test.c b/auto_tests/crypto_test.c index 83f8c525a6..75d94ea1b2 100644 --- a/auto_tests/crypto_test.c +++ b/auto_tests/crypto_test.c @@ -80,6 +80,9 @@ static const uint8_t test_c[147] = { static void test_known(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); + uint8_t c[147]; uint8_t m[131]; @@ -88,12 +91,12 @@ static void test_known(void) 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); + const uint16_t clen = encrypt_data(mem, 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); + const uint16_t mlen = decrypt_data(mem, 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"); @@ -101,6 +104,9 @@ static void test_known(void) static void test_fast_known(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); + uint8_t k[CRYPTO_SHARED_KEY_SIZE]; uint8_t c[147]; uint8_t m[131]; @@ -112,12 +118,12 @@ static void test_fast_known(void) 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); + const uint16_t clen = encrypt_data_symmetric(mem, 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); + const uint16_t mlen = decrypt_data_symmetric(mem, 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"); @@ -125,6 +131,8 @@ static void test_fast_known(void) static void test_endtoend(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); @@ -166,10 +174,10 @@ static void test_endtoend(void) 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); + const uint16_t c1len = encrypt_data(mem, pk2, sk1, n, m, mlen, c1); + const uint16_t c2len = encrypt_data(mem, pk1, sk2, n, m, mlen, c2); + const uint16_t c3len = encrypt_data_symmetric(mem, k1, n, m, mlen, c3); + const uint16_t c4len = encrypt_data_symmetric(mem, 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"); @@ -177,10 +185,10 @@ static void test_endtoend(void) && 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); + const uint16_t m1len = decrypt_data(mem, pk2, sk1, n, c1, c1len, m1); + const uint16_t m2len = decrypt_data(mem, pk1, sk2, n, c1, c1len, m2); + const uint16_t m3len = decrypt_data_symmetric(mem, k1, n, c1, c1len, m3); + const uint16_t m4len = decrypt_data_symmetric(mem, 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"); @@ -192,6 +200,8 @@ static void test_endtoend(void) static void test_large_data(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t k[CRYPTO_SHARED_KEY_SIZE]; @@ -216,13 +226,13 @@ static void test_large_data(void) //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); + const uint16_t c1len = encrypt_data_symmetric(mem, k, n, m1, m1_size, c1); + const uint16_t c2len = encrypt_data_symmetric(mem, 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); + const uint16_t m1plen = decrypt_data_symmetric(mem, 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"); @@ -236,6 +246,8 @@ static void test_large_data(void) static void test_large_data_symmetric(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); uint8_t k[CRYPTO_SYMMETRIC_KEY_SIZE]; @@ -256,10 +268,10 @@ static void test_large_data_symmetric(void) //Generate key new_symmetric_key(rng, k); - const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1); + const uint16_t c1len = encrypt_data_symmetric(mem, 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); + const uint16_t m1plen = decrypt_data_symmetric(mem, 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"); @@ -271,6 +283,8 @@ static void test_large_data_symmetric(void) static void test_very_large_data(void) { + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); const Random *rng = os_random(); ck_assert(rng != nullptr); @@ -287,7 +301,9 @@ static void test_very_large_data(void) ck_assert(plain != nullptr); ck_assert(encrypted != nullptr); - encrypt_data(pk, sk, nonce, plain, plain_size, encrypted); + memset(plain, 0, plain_size); + + encrypt_data(mem, pk, sk, nonce, plain, plain_size, encrypted); free(encrypted); free(plain); diff --git a/auto_tests/encryptsave_test.c b/auto_tests/encryptsave_test.c index e433e410a8..3573337e49 100644 --- a/auto_tests/encryptsave_test.c +++ b/auto_tests/encryptsave_test.c @@ -3,8 +3,6 @@ #include #include -#include - #include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" #include "../toxcore/crypto_core.h" @@ -14,13 +12,10 @@ #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 unsigned char known_key[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}; 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) { @@ -33,20 +28,6 @@ static void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8 } } -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); @@ -101,7 +82,7 @@ static void test_save_friend(void) 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); + memcpy((uint8_t *)key + TOX_PASS_SALT_LENGTH, known_key, TOX_PASS_KEY_LENGTH); size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t *encdata2 = (uint8_t *)malloc(size2); ck_assert(encdata2 != nullptr); @@ -224,7 +205,6 @@ static void test_keys(void) int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); - test_known_kdf(); test_save_friend(); test_keys(); diff --git a/auto_tests/forwarding_test.c b/auto_tests/forwarding_test.c index 75e330a73e..3ba85ed151 100644 --- a/auto_tests/forwarding_test.c +++ b/auto_tests/forwarding_test.c @@ -112,7 +112,7 @@ static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp, Forwarding_Subtox *subtox = (Forwarding_Subtox *)calloc(1, sizeof(Forwarding_Subtox)); ck_assert(subtox != nullptr); - subtox->log = logger_new(); + subtox->log = logger_new(mem); ck_assert(subtox->log != nullptr); logger_callback_log(subtox->log, print_debug_logger, nullptr, index); subtox->mono_time = mono_time_new(mem, nullptr, nullptr); diff --git a/auto_tests/friend_request_test.c b/auto_tests/friend_request_test.c index 7dfc5bf870..18bc5d62b7 100644 --- a/auto_tests/friend_request_test.c +++ b/auto_tests/friend_request_test.c @@ -10,44 +10,57 @@ #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" +#define REQUEST_MESSAGE "Hello, I would like to be your friend. Please respond." + +typedef struct Callback_Data { + Tox *tox1; // request sender + Tox *tox2; // request receiver + uint8_t message[TOX_MAX_FRIEND_REQUEST_LENGTH]; + uint16_t length; +} Callback_Data; -static void accept_friend_request(const Tox_Event_Friend_Request *event, - void *userdata) +static void accept_friend_request(const Tox_Event_Friend_Request *event, void *userdata) { - Tox *state_tox = (Tox *)userdata; + Callback_Data *cb_data = (Callback_Data *)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, + ck_assert_msg(length == cb_data->length && memcmp(cb_data->message, data, cb_data->length) == 0, "unexpected friend request message"); - tox_friend_add_norequest(state_tox, public_key, nullptr); + + fprintf(stderr, "Tox2 accepts friend request.\n"); + + Tox_Err_Friend_Add err; + tox_friend_add_norequest(cb_data->tox2, public_key, &err); + + ck_assert_msg(err == TOX_ERR_FRIEND_ADD_OK, "tox_friend_add_norequest failed: %d", err); } -static void iterate2_wait(const Tox_Dispatch *dispatch, Tox *tox1, Tox *tox2) +static void iterate2_wait(const Tox_Dispatch *dispatch, Callback_Data *cb_data) { Tox_Err_Events_Iterate err; Tox_Events *events; - events = tox_events_iterate(tox1, true, &err); + events = tox_events_iterate(cb_data->tox1, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); - tox_dispatch_invoke(dispatch, events, tox1); + tox_dispatch_invoke(dispatch, events, cb_data); tox_events_free(events); - events = tox_events_iterate(tox2, true, &err); + events = tox_events_iterate(cb_data->tox2, true, &err); ck_assert(err == TOX_ERR_EVENTS_ITERATE_OK); - tox_dispatch_invoke(dispatch, events, tox2); + tox_dispatch_invoke(dispatch, events, cb_data); tox_events_free(events); c_sleep(ITERATION_INTERVAL); } -static void test_friend_request(void) +static void test_friend_request(const uint8_t *message, uint16_t length) { printf("Initialising 2 toxes.\n"); uint32_t index[] = { 1, 2 }; @@ -60,7 +73,7 @@ static void test_friend_request(void) tox_events_init(tox1); tox_events_init(tox2); - printf("Bootstrapping tox2 off tox1.\n"); + 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); @@ -70,25 +83,36 @@ static void test_friend_request(void) Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); ck_assert(dispatch != nullptr); + Callback_Data cb_data = {nullptr}; + cb_data.tox1 = tox1; + cb_data.tox2 = tox2; + + ck_assert(length <= sizeof(cb_data.message)); + memcpy(cb_data.message, message, length); + cb_data.length = length; + do { - iterate2_wait(dispatch, tox1, tox2); + iterate2_wait(dispatch, &cb_data); } 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"); + printf("Tox1 adds Tox2 as friend. Waiting for Tox2 to accept.\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); + Tox_Err_Friend_Add err; + const uint32_t test = tox_friend_add(tox1, address, message, length, &err); + + ck_assert_msg(err == TOX_ERR_FRIEND_ADD_OK, "tox_friend_add failed: %d", err); ck_assert_msg(test == 0, "failed to add friend error code: %u", test); do { - iterate2_wait(dispatch, tox1, tox2); + iterate2_wait(dispatch, &cb_data); } while (tox_friend_get_connection_status(tox1, 0, nullptr) != TOX_CONNECTION_UDP || tox_friend_get_connection_status(tox2, 0, nullptr) != TOX_CONNECTION_UDP); @@ -104,6 +128,20 @@ int main(void) { setvbuf(stdout, nullptr, _IONBF, 0); - test_friend_request(); + fprintf(stderr, "Testing friend request with the smallest allowed message length.\n"); + test_friend_request((const uint8_t *)"a", 1); + + fprintf(stderr, "Testing friend request with an average sized message length.\n"); + test_friend_request((const uint8_t *)REQUEST_MESSAGE, sizeof(REQUEST_MESSAGE) - 1); + + uint8_t long_message[TOX_MAX_FRIEND_REQUEST_LENGTH]; + + for (uint16_t i = 0; i < sizeof(long_message); ++i) { + long_message[i] = 'a'; + } + + fprintf(stderr, "Testing friend request with the largest allowed message length.\n"); + test_friend_request(long_message, sizeof(long_message)); + return 0; } diff --git a/auto_tests/group_general_test.c b/auto_tests/group_general_test.c index a4a4a0fed8..9e953e5a38 100644 --- a/auto_tests/group_general_test.c +++ b/auto_tests/group_general_test.c @@ -392,9 +392,9 @@ static void group_announce_test(AutoTox *autotoxes) 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); + Tox_Err_Group_Join err_rejoin; + tox_group_join(tox0, chat_id, (const uint8_t *)PEER0_NICK, PEER0_NICK_LEN, nullptr, 0, &err_rejoin); + ck_assert(err_rejoin == TOX_ERR_GROUP_JOIN_OK); while (state1->peer_joined_count != 2 && state0->self_joined_count == 2) { iterate_all_wait(autotoxes, NUM_GROUP_TOXES, ITERATION_INTERVAL); diff --git a/auto_tests/group_message_test.c b/auto_tests/group_message_test.c index 608cebf844..380a994b56 100644 --- a/auto_tests/group_message_test.c +++ b/auto_tests/group_message_test.c @@ -284,7 +284,7 @@ static void group_private_message_handler(const Tox_Event_Group_Private_Message 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_type(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); diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c index 76cb94a17f..a2bc301a2f 100644 --- a/auto_tests/network_test.c +++ b/auto_tests/network_test.c @@ -23,12 +23,15 @@ static void test_addr_resolv_localhost(void) const Network *ns = os_network(); ck_assert(ns != nullptr); + const Memory *mem = os_memory(); + ck_assert(mem != nullptr); + const char localhost[] = "localhost"; IP ip; ip_init(&ip, 0); // ipv6enabled = 0 - bool res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr); + bool res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, nullptr, true); int error = net_error(); char *strerror = net_new_strerror(error); @@ -42,14 +45,14 @@ static void test_addr_resolv_localhost(void) net_ip_ntoa(&ip, &ip_str)); ip_init(&ip, 1); // ipv6enabled = 1 - res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr); + res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, nullptr, true); #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); + res = addr_resolve_or_parse_ip(ns, mem, "ip6-localhost", &ip, nullptr, true); localhost_split = 1; } @@ -75,7 +78,7 @@ static void test_addr_resolv_localhost(void) ip.family = net_family_unspec(); IP extra; ip_reset(&extra); - res = addr_resolve_or_parse_ip(ns, localhost, &ip, &extra); + res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, &extra, true); error = net_error(); strerror = net_new_strerror(error); ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror); diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 3a81df41b8..b73ffbd165 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c @@ -109,7 +109,7 @@ static int handle_test_3(void *object, const IP_Port *source, const uint8_t *pac #if 0 print_client_id(packet, length); #endif - int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht), + int len = decrypt_data(onion->mem, 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); @@ -144,7 +144,7 @@ static int handle_test_3_old(void *object, const IP_Port *source, const uint8_t #if 0 print_client_id(packet, length); #endif - int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht), + int len = decrypt_data(onion->mem, 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); @@ -182,7 +182,7 @@ static int handle_test_4(void *object, const IP_Port *source, const uint8_t *pac return 1; } - int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, dht_get_self_secret_key(onion->dht), packet + 1, + int len = decrypt_data(onion->mem, 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) { @@ -202,10 +202,10 @@ static int handle_test_4(void *object, const IP_Port *source, const uint8_t *pac * 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) +static void send_onion_packet(const Networking_Core *net, const Memory *mem, 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); + const int len = create_onion_packet(mem, 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"); } @@ -228,9 +228,9 @@ static void test_basic(void) const Random *rng = os_random(); ck_assert(rng != nullptr); - Logger *log1 = logger_new(); + Logger *log1 = logger_new(mem); logger_callback_log(log1, print_debug_logger, nullptr, &index[0]); - Logger *log2 = logger_new(); + Logger *log2 = logger_new(mem); logger_callback_log(log2, print_debug_logger, nullptr, &index[1]); Mono_Time *mono_time1 = mono_time_new(mem, nullptr, nullptr); @@ -264,7 +264,7 @@ static void test_basic(void) 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)); + send_onion_packet(onion1->net, onion1->mem, rng, &path, &nodes[3].ip_port, req_packet, sizeof(req_packet)); handled_test_1 = 0; @@ -291,7 +291,7 @@ static void test_basic(void) 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], + int ret = send_announce_request(log1, onion1->mem, onion1->net, rng, &path, &nodes[3], dht_get_self_public_key(onion1->dht), dht_get_self_secret_key(onion1->dht), zeroes, @@ -313,7 +313,7 @@ static void test_basic(void) 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], + send_announce_request(log1, onion1->mem, onion1->net, rng, &path, &nodes[3], dht_get_self_public_key(onion1->dht), dht_get_self_secret_key(onion1->dht), test_3_ping_id, @@ -329,7 +329,7 @@ static void test_basic(void) CRYPTO_PUBLIC_KEY_SIZE) != 0); c_sleep(1000); - Logger *log3 = logger_new(); + Logger *log3 = logger_new(mem); logger_callback_log(log3, print_debug_logger, nullptr, &index[2]); Mono_Time *mono_time3 = mono_time_new(mem, nullptr, nullptr); @@ -338,7 +338,7 @@ static void test_basic(void) 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, + ret = send_data_request(log3, onion3->mem, 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")); @@ -412,7 +412,7 @@ static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, u return nullptr; } - on->log = logger_new(); + on->log = logger_new(mem); if (!on->log) { free(on); diff --git a/auto_tests/tox_loop_test.c b/auto_tests/tox_loop_test.c new file mode 100644 index 0000000000..8e0b0fd2ea --- /dev/null +++ b/auto_tests/tox_loop_test.c @@ -0,0 +1,128 @@ +#include +#include +#include + +#include "../toxcore/tox.h" + +#include "check_compat.h" +#include "../testing/misc_tools.h" + +/* The CI containers respond poorly to ::1 as a localhost address + * You're encouraged to -D FORCE_TESTS_IPV6 on a local test */ +#ifdef TOX_LOCALHOST +#undef TOX_LOCALHOST +#endif +#ifdef FORCE_TESTS_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 + +typedef struct Loop_Test { + int start_count; + int stop_count; + pthread_mutex_t mutex; + Tox *tox; +} Loop_Test; + +static void tox_loop_cb_start(Tox *tox, void *data) +{ + Loop_Test *userdata = (Loop_Test *)data; + pthread_mutex_lock(&userdata->mutex); + ++userdata->start_count; +} + +static void tox_loop_cb_stop(Tox *tox, void *data) +{ + Loop_Test *userdata = (Loop_Test *)data; + ++userdata->stop_count; + pthread_mutex_unlock(&userdata->mutex); +} + +static void *tox_loop_worker(void *data) +{ + Loop_Test *userdata = (Loop_Test *)data; + Tox_Err_Loop err; + tox_loop(userdata->tox, userdata, &err); + ck_assert_msg(err == TOX_ERR_LOOP_OK, "tox_loop error: %d", err); + return nullptr; +} + +static void test_tox_loop(void) +{ + pthread_t worker, worker_tcp; + Tox_Err_Options_New err_opts; + struct Tox_Options *opts = tox_options_new(&err_opts); + ck_assert_msg(err_opts == TOX_ERR_OPTIONS_NEW_OK, "tox_options_new: %d\n", err_opts); + tox_options_set_experimental_thread_safety(opts, true); + + Loop_Test *userdata = (Loop_Test *)calloc(1, sizeof(Loop_Test)); + ck_assert(userdata != nullptr); + uint8_t dpk[TOX_PUBLIC_KEY_SIZE]; + + userdata->start_count = 0; + userdata->stop_count = 0; + pthread_mutex_init(&userdata->mutex, nullptr); + + tox_options_set_tcp_port(opts, TCP_RELAY_PORT); + Tox_Err_New err_new; + userdata->tox = tox_new(opts, &err_new); + ck_assert_msg(err_new == TOX_ERR_NEW_OK, "tox_new: %d\n", err_new); + tox_callback_loop_begin(userdata->tox, tox_loop_cb_start); + tox_callback_loop_end(userdata->tox, tox_loop_cb_stop); + pthread_create(&worker, nullptr, tox_loop_worker, userdata); + + tox_self_get_dht_id(userdata->tox, dpk); + + tox_options_default(opts); + tox_options_set_experimental_thread_safety(opts, true); + Loop_Test userdata_tcp; + userdata_tcp.start_count = 0; + userdata_tcp.stop_count = 0; + pthread_mutex_init(&userdata_tcp.mutex, nullptr); + userdata_tcp.tox = tox_new(opts, &err_new); + ck_assert_msg(err_new == TOX_ERR_NEW_OK, "tox_new: %d\n", err_new); + tox_callback_loop_begin(userdata_tcp.tox, tox_loop_cb_start); + tox_callback_loop_end(userdata_tcp.tox, tox_loop_cb_stop); + pthread_create(&worker_tcp, nullptr, tox_loop_worker, &userdata_tcp); + + pthread_mutex_lock(&userdata_tcp.mutex); + Tox_Err_Bootstrap error; + ck_assert_msg(tox_add_tcp_relay(userdata_tcp.tox, TOX_LOCALHOST, TCP_RELAY_PORT, dpk, &error), "Add relay error, %i", + error); + ck_assert_msg(tox_bootstrap(userdata_tcp.tox, TOX_LOCALHOST, 33445, dpk, &error), "Bootstrap error, %i", error); + pthread_mutex_unlock(&userdata_tcp.mutex); + + c_sleep(1000); + + tox_loop_stop(userdata->tox); + void *retval = nullptr; + pthread_join(worker, &retval); + ck_assert_msg((uintptr_t)retval == 0, "tox_loop didn't return 0"); + + tox_kill(userdata->tox); + ck_assert_msg(userdata->start_count == userdata->stop_count, "start and stop must match (start = %d, stop = %d)", + userdata->start_count, userdata->stop_count); + + tox_loop_stop(userdata_tcp.tox); + pthread_join(worker_tcp, &retval); + ck_assert_msg((uintptr_t)retval == 0, "tox_loop didn't return 0"); + + tox_kill(userdata_tcp.tox); + ck_assert_msg(userdata_tcp.start_count == userdata_tcp.stop_count, "start and stop must match (start = %d, stop = %d)", + userdata_tcp.start_count, userdata_tcp.stop_count); + + tox_options_free(opts); + free(userdata); +} + +int main(int argc, char *argv[]) +{ + test_tox_loop(); + return 0; +} diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c index 2892f7245c..fe1a1033c6 100644 --- a/auto_tests/toxav_many_test.c +++ b/auto_tests/toxav_many_test.c @@ -168,29 +168,33 @@ static void test_av_three_calls(void) 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(nullptr, &error, &index[0]); + 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(nullptr, &error, &index[1]); + 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(nullptr, &error, &index[2]); + 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(nullptr, &error, &index[3]); + 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(nullptr, &error, &index[4]); + 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"); diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 941bc33158..9313566e37 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,15 +1,25 @@ pool: vmImage: "windows-2019" jobs: - - job: "windows_msvc_conan" + - job: "vcpkg" strategy: matrix: static: - conan.shared: "False" + ENABLE_STATIC: "ON" + ENABLE_SHARED: "OFF" shared: - conan.shared: "True" + ENABLE_STATIC: "OFF" + ENABLE_SHARED: "ON" steps: - - bash: python -m pip install conan==1.59.0 + - task: Cache@2 + inputs: + key: "vcpkg" + path: "_build/vcpkg_installed" - 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 + - bash: cmake --preset windows-default -DENABLE_STATIC=$(ENABLE_STATIC) -DENABLE_SHARED=$(ENABLE_SHARED) + env: + VCPKG_ROOT: "C:/vcpkg" + VCPKG_DEFAULT_TRIPLET: "x64-windows" + - bash: cmake --build _build --config Release + - bash: ctest --preset windows-default -C Release --parallel 50 || + ctest --preset windows-default -C Release --rerun-failed --output-on-failure diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 900e9b185a..fb30fdcefa 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -12,14 +12,20 @@ find_library(SOCKET_LIBRARIES socket) find_package(pthreads QUIET) if(NOT TARGET PThreads4W::PThreads4W) + find_package(pthreads4w QUIET) +endif() +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) +pkg_search_module(LIBSODIUM libsodium IMPORTED_TARGET) if(MSVC) - find_package(unofficial-sodium REQUIRED) + find_package(libsodium) + if(NOT TARGET libsodium::libsodium) + find_package(unofficial-sodium REQUIRED) + endif() endif() # For toxav. @@ -27,10 +33,23 @@ pkg_search_module(OPUS opus IMPORTED_TARGET) if(NOT OPUS_FOUND) pkg_search_module(OPUS Opus IMPORTED_TARGET) endif() +if(NOT OPUS_FOUND) + find_package(Opus) + if(TARGET Opus::opus) + set(OPUS_FOUND TRUE) + endif() +endif() + pkg_search_module(VPX vpx IMPORTED_TARGET) if(NOT VPX_FOUND) pkg_search_module(VPX libvpx IMPORTED_TARGET) endif() +if(NOT VPX_FOUND) + find_package(libvpx) + if(TARGET libvpx::libvpx) + set(VPX_FOUND TRUE) + endif() +endif() # For tox-bootstrapd. pkg_search_module(LIBCONFIG libconfig IMPORTED_TARGET) diff --git a/conanfile.py b/conanfile.py deleted file mode 100644 index e9af70b5c9..0000000000 --- a/conanfile.py +++ /dev/null @@ -1,87 +0,0 @@ -# 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"] diff --git a/configure.ac b/configure.ac index 8f9a50bb3f..b2869a9cd7 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([tox], [0.2.18]) +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]) diff --git a/other/BUILD.bazel b/other/BUILD.bazel index 50693bda43..3239c5c174 100644 --- a/other/BUILD.bazel +++ b/other/BUILD.bazel @@ -21,10 +21,15 @@ cc_binary( "//c-toxcore/toxcore:Messenger", "//c-toxcore/toxcore:TCP_server", "//c-toxcore/toxcore:ccompat", + "//c-toxcore/toxcore:crypto_core", + "//c-toxcore/toxcore:forwarding", + "//c-toxcore/toxcore:group_announce", "//c-toxcore/toxcore:group_onion_announce", "//c-toxcore/toxcore:logger", + "//c-toxcore/toxcore:mem", "//c-toxcore/toxcore:mono_time", "//c-toxcore/toxcore:network", + "//c-toxcore/toxcore:onion", "//c-toxcore/toxcore:onion_announce", "//c-toxcore/toxcore:tox", ], diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c index 8a15fb5e00..c4511aa1f2 100644 --- a/other/DHT_bootstrap.c +++ b/other/DHT_bootstrap.c @@ -144,16 +144,16 @@ int main(int argc, char *argv[]) IP ip; ip_init(&ip, ipv6enabled); - Logger *logger = logger_new(); + const Random *rng = os_random(); + const Network *ns = os_network(); + const Memory *mem = os_memory(); + + Logger *logger = logger_new(mem); if (MIN_LOGGER_LEVEL <= LOGGER_LEVEL_DEBUG) { logger_callback_log(logger, print_log, nullptr, nullptr); } - const Random *rng = os_random(); - const Network *ns = os_network(); - const Memory *mem = os_memory(); - Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); const uint16_t start_port = PORT; const uint16_t end_port = start_port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM); @@ -228,9 +228,12 @@ int main(int argc, char *argv[]) const uint16_t port = net_htons((uint16_t)port_conv); + // TODO(iphydf): Maybe disable and only use IP addresses? + const bool dns_enabled = true; + uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]); const bool res = dht_bootstrap_from_address(dht, argv[argvoffset + 1], - ipv6enabled, port, bootstrap_key); + ipv6enabled, dns_enabled, port, bootstrap_key); free(bootstrap_key); if (!res) { diff --git a/other/analysis/gen-file.sh b/other/analysis/gen-file.sh index 10edd0b531..586a90c6b4 100644 --- a/other/analysis/gen-file.sh +++ b/other/analysis/gen-file.sh @@ -15,7 +15,7 @@ CPPFLAGS+=("-Itoxav") CPPFLAGS+=("-Itoxencryptsave") CPPFLAGS+=("-Ithird_party/cmp") -LDFLAGS=("-lopus" "-lsodium" "-lvpx" "-lpthread" "-lconfig" "-lgmock" "-lgtest") +LDFLAGS=("-lopus" "-lsodium" "-lvpx" "-lpthread" "-lconfig" "-lgmock" "-lgtest" "-lbenchmark" "-lev") LDFLAGS+=("-fuse-ld=gold") LDFLAGS+=("-Wl,--detect-odr-violations") LDFLAGS+=("-Wl,--warn-common") @@ -27,7 +27,7 @@ put() { if [ "$SKIP_LINES" = "" ]; then echo "#line 1 \"$1\"" >>amalgamation.cc fi - cat "$1" >>amalgamation.cc + grep -v '^BENCHMARK_MAIN' "$1" >>amalgamation.cc } putmain() { diff --git a/other/analysis/run-clang b/other/analysis/run-clang index f5ec50f4a2..3f7113b49a 100755 --- a/other/analysis/run-clang +++ b/other/analysis/run-clang @@ -27,9 +27,10 @@ run() { -Wno-missing-noreturn \ -Wno-old-style-cast \ -Wno-padded \ - -Wno-sign-compare \ + -Wno-switch-default \ -Wno-tautological-pointer-compare \ -Wno-unreachable-code-return \ + -Wno-unsafe-buffer-usage \ -Wno-unused-parameter \ -Wno-used-but-marked-unused \ -Wno-source-uses-openmp diff --git a/other/analysis/run-clang-tidy b/other/analysis/run-clang-tidy index bcdb78f5b8..cbba205994 100755 --- a/other/analysis/run-clang-tidy +++ b/other/analysis/run-clang-tidy @@ -79,6 +79,9 @@ CHECKS="$CHECKS,-clang-diagnostic-tautological-pointer-compare" # [unreadVariable] CHECKS="$CHECKS,-cppcoreguidelines-init-variables" +# Used by libev. +CHECKS="$CHECKS,-hicpp-no-assembler" + # Short variable names are used quite a lot, and we don't consider them a # readability issue. CHECKS="$CHECKS,-readability-identifier-length" diff --git a/other/analysis/run-cppcheck b/other/analysis/run-cppcheck index 7e341f698d..03c597d709 100755 --- a/other/analysis/run-cppcheck +++ b/other/analysis/run-cppcheck @@ -20,8 +20,6 @@ CPPCHECK+=("--suppress=knownConditionTrueFalse") CPPCHECK+=("--suppress=missingIncludeSystem") # TODO(iphydf): Maybe fix? CPPCHECK+=("--suppress=signConversion") -# TODO(iphydf): Fixed in the toxav refactor PR. -CPPCHECK+=("--suppress=redundantAssignment") # We use this for VLAs. CPPCHECK_CXX+=("--suppress=allocaCalled") diff --git a/other/analysis/variants.sh b/other/analysis/variants.sh index 6a8241bae9..7e04a450a5 100644 --- a/other/analysis/variants.sh +++ b/other/analysis/variants.sh @@ -1,3 +1,5 @@ #!/bin/bash -run +run "$@" +#run -DVANILLA_NACL -I/usr/include/sodium "$@" +run -DHAVE_LIBEV "$@" diff --git a/other/bootstrap_daemon/BUILD.bazel b/other/bootstrap_daemon/BUILD.bazel index 6d4b157b17..4c65660548 100644 --- a/other/bootstrap_daemon/BUILD.bazel +++ b/other/bootstrap_daemon/BUILD.bazel @@ -6,16 +6,24 @@ cc_binary( "src/*.c", "src/*.h", ]), + tags = ["no-windows"], deps = [ "//c-toxcore/other:bootstrap_node_packets", "//c-toxcore/toxcore:DHT", "//c-toxcore/toxcore:LAN_discovery", "//c-toxcore/toxcore:TCP_server", "//c-toxcore/toxcore:announce", + "//c-toxcore/toxcore:attributes", "//c-toxcore/toxcore:ccompat", + "//c-toxcore/toxcore:crypto_core", + "//c-toxcore/toxcore:forwarding", + "//c-toxcore/toxcore:group_announce", "//c-toxcore/toxcore:group_onion_announce", "//c-toxcore/toxcore:logger", + "//c-toxcore/toxcore:mem", "//c-toxcore/toxcore:mono_time", + "//c-toxcore/toxcore:network", + "//c-toxcore/toxcore:onion", "//c-toxcore/toxcore:onion_announce", "//c-toxcore/toxcore:tox", "@libconfig", diff --git a/other/bootstrap_daemon/docker/Dockerfile b/other/bootstrap_daemon/docker/Dockerfile index 1cbaf4c0ae..3d150e02f6 100644 --- a/other/bootstrap_daemon/docker/Dockerfile +++ b/other/bootstrap_daemon/docker/Dockerfile @@ -5,11 +5,11 @@ FROM alpine:3.19.0 AS build RUN ["apk", "--no-cache", "add",\ "clang",\ "cmake",\ - "linux-headers",\ "libconfig-dev",\ "libconfig-static",\ "libsodium-dev",\ "libsodium-static",\ + "linux-headers",\ "musl-dev",\ "ninja",\ "python3"] diff --git a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 index faef8b8690..33ace212cb 100644 --- a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 +++ b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 @@ -1 +1 @@ -af58a125e5c80d7a19bc7f32868c1edfdf80f366e3bf778728961a50ce63ee26 /usr/local/bin/tox-bootstrapd +9ec2993a28988bd147bf8f4f21a824c2fc5dbf7255e391b3ce517d337ebce5c1 /usr/local/bin/tox-bootstrapd diff --git a/other/bootstrap_daemon/src/config.c b/other/bootstrap_daemon/src/config.c index 891912dce1..19779c5f76 100644 --- a/other/bootstrap_daemon/src/config.c +++ b/other/bootstrap_daemon/src/config.c @@ -138,9 +138,20 @@ static void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_por } } +// A wrapper function that actually takes a bool argument +static int tox_config_lookup_bool(const config_t *config, const char *path, bool *bool_value) +{ + int int_value = 0; + if (config_lookup_bool(config, path, &int_value) == CONFIG_FALSE) { + return CONFIG_FALSE; + } + *bool_value = int_value != 0; + return CONFIG_TRUE; +} + bool get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, - int *enable_ipv6, int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, - uint16_t **tcp_relay_ports, int *tcp_relay_port_count, int *enable_motd, char **motd) + bool *enable_ipv6, bool *enable_ipv4_fallback, bool *enable_lan_discovery, bool *enable_tcp_relay, + uint16_t **tcp_relay_ports, int *tcp_relay_port_count, bool *enable_motd, char **motd) { config_t cfg; @@ -200,19 +211,21 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char ** *keys_file_path = (char *)malloc(keys_file_path_len); if (*keys_file_path == nullptr) { log_write(LOG_LEVEL_ERROR, "Allocation failure.\n"); + free(*pid_file_path); + *pid_file_path = nullptr; return false; } memcpy(*keys_file_path, tmp_keys_file, keys_file_path_len); // Get IPv6 option - if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) { + if (tox_config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) { log_write(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6); log_write(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false"); *enable_ipv6 = DEFAULT_ENABLE_IPV6; } // Get IPv4 fallback option - if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) { + if (tox_config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) { log_write(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK); log_write(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false"); @@ -220,7 +233,7 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char ** } // Get LAN discovery option - if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) { + if (tox_config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) { log_write(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY); log_write(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false"); @@ -228,28 +241,28 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char ** } // Get TCP relay option - if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) { + if (tox_config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) { log_write(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY); log_write(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY, DEFAULT_ENABLE_TCP_RELAY ? "true" : "false"); *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY; } - if (*enable_tcp_relay != 0) { + if (*enable_tcp_relay) { parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count); } else { *tcp_relay_port_count = 0; } // Get MOTD option - if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) { + if (tox_config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) { log_write(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD); log_write(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD, DEFAULT_ENABLE_MOTD ? "true" : "false"); *enable_motd = DEFAULT_ENABLE_MOTD; } - if (*enable_motd != 0) { + if (*enable_motd) { // Get MOTD const char *tmp_motd; @@ -271,14 +284,14 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char ** log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path); log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path); log_write(LOG_LEVEL_INFO, "'%s': %d\n", NAME_PORT, *port); - log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 != 0 ? "true" : "false"); - log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback != 0 ? "true" : "false"); - log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery != 0 ? "true" : "false"); + log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false"); + log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false"); + log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false"); - log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay != 0 ? "true" : "false"); + log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false"); // Show info about tcp ports only if tcp relay is enabled - if (*enable_tcp_relay != 0) { + if (*enable_tcp_relay) { if (*tcp_relay_port_count == 0) { log_write(LOG_LEVEL_ERROR, "No TCP ports could be read.\n"); } else { @@ -290,9 +303,9 @@ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char ** } } - log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd != 0 ? "true" : "false"); + log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false"); - if (*enable_motd != 0) { + if (*enable_motd) { log_write(LOG_LEVEL_INFO, "'%s': %s\n", NAME_MOTD, *motd); } @@ -377,6 +390,9 @@ bool bootstrap_from_config(const char *cfg_file_path, DHT *dht, bool enable_ipv6 bool address_resolved; uint8_t *bs_public_key_bin; + // TODO(iphydf): Maybe disable it and only use IP addresses? + const bool dns_enabled = true; + node = config_setting_get_elem(node_list, 0); if (node == nullptr) { @@ -416,7 +432,7 @@ bool bootstrap_from_config(const char *cfg_file_path, DHT *dht, bool enable_ipv6 } bs_public_key_bin = bootstrap_hex_string_to_bin(bs_public_key); - address_resolved = dht_bootstrap_from_address(dht, bs_address, enable_ipv6, net_htons(bs_port), + address_resolved = dht_bootstrap_from_address(dht, bs_address, enable_ipv6, dns_enabled, net_htons(bs_port), bs_public_key_bin); free(bs_public_key_bin); diff --git a/other/bootstrap_daemon/src/config.h b/other/bootstrap_daemon/src/config.h index be1e57aa51..677dde5c8b 100644 --- a/other/bootstrap_daemon/src/config.h +++ b/other/bootstrap_daemon/src/config.h @@ -17,14 +17,14 @@ * * Important: You are responsible for freeing `pid_file_path` and `keys_file_path` * also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports` - * and also `motd` iff `enable_motd` is set. + * and also `motd` iff `enable_motd` is true. * * @return true on success, * false on failure, doesn't modify any data pointed by arguments. */ bool get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, - int *enable_ipv6, int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, - uint16_t **tcp_relay_ports, int *tcp_relay_port_count, int *enable_motd, char **motd); + bool *enable_ipv6, bool *enable_ipv4_fallback, bool *enable_lan_discovery, bool *enable_tcp_relay, + uint16_t **tcp_relay_ports, int *tcp_relay_port_count, bool *enable_motd, char **motd); /** * Bootstraps off nodes listed in the config file. diff --git a/other/bootstrap_daemon/src/config_defaults.h b/other/bootstrap_daemon/src/config_defaults.h index 2e2c94f804..68f444f187 100644 --- a/other/bootstrap_daemon/src/config_defaults.h +++ b/other/bootstrap_daemon/src/config_defaults.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2023 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2014-2016 Tox project. */ @@ -10,17 +10,19 @@ #ifndef C_TOXCORE_OTHER_BOOTSTRAP_DAEMON_SRC_CONFIG_DEFAULTS_H #define C_TOXCORE_OTHER_BOOTSTRAP_DAEMON_SRC_CONFIG_DEFAULTS_H +#include + #include "global.h" #define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid" #define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys" #define DEFAULT_PORT 33445 -#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false -#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false -#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false -#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false +#define DEFAULT_ENABLE_IPV6 true +#define DEFAULT_ENABLE_IPV4_FALLBACK true +#define DEFAULT_ENABLE_LAN_DISCOVERY true +#define DEFAULT_ENABLE_TCP_RELAY true #define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports -#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false +#define DEFAULT_ENABLE_MOTD true #define DEFAULT_MOTD DAEMON_NAME #endif // C_TOXCORE_OTHER_BOOTSTRAP_DAEMON_SRC_CONFIG_DEFAULTS_H diff --git a/other/bootstrap_daemon/src/tox-bootstrapd.c b/other/bootstrap_daemon/src/tox-bootstrapd.c index 44a9c282c4..e29afe5c2b 100644 --- a/other/bootstrap_daemon/src/tox-bootstrapd.c +++ b/other/bootstrap_daemon/src/tox-bootstrapd.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2014-2016 Tox project. */ @@ -240,13 +240,13 @@ int main(int argc, char *argv[]) char *pid_file_path = nullptr; char *keys_file_path = nullptr; int start_port = 0; - int enable_ipv6 = 0; - int enable_ipv4_fallback = 0; - int enable_lan_discovery = 0; - int enable_tcp_relay = 0; + bool enable_ipv6 = false; + bool enable_ipv4_fallback = false; + bool enable_lan_discovery = false; + bool enable_tcp_relay = false; uint16_t *tcp_relay_ports = nullptr; int tcp_relay_port_count = 0; - int enable_motd = 0; + bool enable_motd = false; char *motd = nullptr; if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &start_port, &enable_ipv6, &enable_ipv4_fallback, @@ -281,25 +281,26 @@ int main(int argc, char *argv[]) free(pid_file_path); IP ip; - ip_init(&ip, enable_ipv6 != 0); + ip_init(&ip, enable_ipv6); - Logger *logger = logger_new(); + const Memory *mem = os_memory(); + const Random *rng = os_random(); + const Network *ns = os_network(); + + Logger *logger = logger_new(mem); if (MIN_LOGGER_LEVEL <= LOGGER_LEVEL_DEBUG) { logger_callback_log(logger, toxcore_logger_callback, nullptr, nullptr); } const uint16_t end_port = start_port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM); - const Memory *mem = os_memory(); - const Random *rng = os_random(); - const Network *ns = os_network(); Networking_Core *net = new_networking_ex(logger, mem, ns, &ip, start_port, end_port, nullptr); if (net == nullptr) { - if (enable_ipv6 != 0 && enable_ipv4_fallback != 0) { + if (enable_ipv6 && enable_ipv4_fallback) { log_write(LOG_LEVEL_WARNING, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n"); - enable_ipv6 = 0; - ip_init(&ip, enable_ipv6 != 0); + enable_ipv6 = false; + ip_init(&ip, enable_ipv6); net = new_networking_ex(logger, mem, ns, &ip, start_port, end_port, nullptr); if (net == nullptr) { @@ -334,7 +335,7 @@ int main(int argc, char *argv[]) mono_time_update(mono_time); - DHT *const dht = new_dht(logger, mem, rng, ns, mono_time, net, true, enable_lan_discovery != 0); + DHT *const dht = new_dht(logger, mem, rng, ns, mono_time, net, true, enable_lan_discovery); if (dht == nullptr) { log_write(LOG_LEVEL_ERROR, "Couldn't initialize Tox DHT instance. Exiting.\n"); @@ -429,7 +430,7 @@ int main(int argc, char *argv[]) gca_onion_init(group_announce, onion_a); - if (enable_motd != 0) { + if (enable_motd) { if (bootstrap_set_callbacks(dht_get_net(dht), DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) { log_write(LOG_LEVEL_INFO, "Set MOTD successfully.\n"); free(motd); @@ -472,7 +473,7 @@ int main(int argc, char *argv[]) TCP_Server *tcp_server = nullptr; - if (enable_tcp_relay != 0) { + if (enable_tcp_relay) { if (tcp_relay_port_count == 0) { log_write(LOG_LEVEL_ERROR, "No TCP relay ports read. Exiting.\n"); kill_onion_announce(onion_a); @@ -488,7 +489,7 @@ int main(int argc, char *argv[]) return 1; } - tcp_server = new_tcp_server(logger, mem, rng, ns, enable_ipv6 != 0, + tcp_server = new_tcp_server(logger, mem, rng, ns, enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht_get_self_secret_key(dht), onion, forwarding); @@ -535,7 +536,7 @@ int main(int argc, char *argv[]) } } - if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6 != 0)) { + if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) { log_write(LOG_LEVEL_INFO, "List of bootstrap nodes read successfully.\n"); } else { log_write(LOG_LEVEL_ERROR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path); @@ -561,7 +562,7 @@ int main(int argc, char *argv[]) Broadcast_Info *broadcast = nullptr; - if (enable_lan_discovery != 0) { + if (enable_lan_discovery) { broadcast = lan_discovery_init(ns); log_write(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n"); } @@ -589,12 +590,12 @@ int main(int argc, char *argv[]) do_dht(dht); - if (enable_lan_discovery != 0 && mono_time_is_timeout(mono_time, last_lan_discovery, LAN_DISCOVERY_INTERVAL)) { + if (enable_lan_discovery && mono_time_is_timeout(mono_time, last_lan_discovery, LAN_DISCOVERY_INTERVAL)) { lan_discovery_send(dht_get_net(dht), broadcast, dht_get_self_public_key(dht), net_htons_port); last_lan_discovery = mono_time_get(mono_time); } - if (enable_tcp_relay != 0) { + if (enable_tcp_relay) { do_tcp_server(tcp_server, mono_time); } @@ -618,7 +619,7 @@ int main(int argc, char *argv[]) break; default: - log_write(LOG_LEVEL_INFO, "Received (%d) signal. Exiting.\n", caught_signal); + log_write(LOG_LEVEL_INFO, "Received (%ld) signal. Exiting.\n", (long)caught_signal); } lan_discovery_kill(broadcast); diff --git a/other/bootstrap_daemon/websocket/websockify/go.mod b/other/bootstrap_daemon/websocket/websockify/go.mod index 6db72397b2..aa291f6fe9 100644 --- a/other/bootstrap_daemon/websocket/websockify/go.mod +++ b/other/bootstrap_daemon/websocket/websockify/go.mod @@ -1,7 +1,7 @@ module github.com/TokTok/c-toxcore/other/bootstrap_daemon/websocket/websockify -go 1.17 +go 1.20 -require github.com/gorilla/websocket v1.5.1 +require github.com/gorilla/websocket v1.5.3 -require golang.org/x/net v0.17.0 // indirect +require golang.org/x/net v0.33.0 // indirect diff --git a/other/bootstrap_daemon/websocket/websockify/go.sum b/other/bootstrap_daemon/websocket/websockify/go.sum index 487893c99c..b147484d65 100644 --- a/other/bootstrap_daemon/websocket/websockify/go.sum +++ b/other/bootstrap_daemon/websocket/websockify/go.sum @@ -4,6 +4,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -11,8 +13,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -24,17 +28,22 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/other/docker/circleci/Dockerfile b/other/docker/circleci/Dockerfile index 3b23eed793..cb431c3d9f 100644 --- a/other/docker/circleci/Dockerfile +++ b/other/docker/circleci/Dockerfile @@ -1,18 +1,18 @@ ################################################ # cmake-asan -FROM ubuntu:20.04 +FROM ubuntu:24.04 RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \ clang \ cmake \ + libclang-rt-dev \ libconfig-dev \ libgmock-dev \ libgtest-dev \ libopus-dev \ libsodium-dev \ libvpx-dev \ - llvm-dev \ ninja-build \ pkg-config \ && apt-get clean \ @@ -22,8 +22,8 @@ COPY entrypoint.sh / RUN ["chmod", "755", "/entrypoint.sh"] WORKDIR /home/builder -RUN groupadd -r -g 1000 builder \ - && useradd --no-log-init -r -g builder -u 1000 builder \ +RUN groupadd -r -g 987 builder \ + && useradd --no-log-init -r -g builder -u 987 builder \ && chown builder:builder /home/builder USER builder diff --git a/other/docker/circleci/entrypoint.sh b/other/docker/circleci/entrypoint.sh index 971759235f..0788e71d51 100755 --- a/other/docker/circleci/entrypoint.sh +++ b/other/docker/circleci/entrypoint.sh @@ -1,9 +1,9 @@ #!/bin/sh -set -eu +set -eux SANITIZER="${1:-asan}" cp -a /c-toxcore . cd c-toxcore -.circleci/cmake-"$SANITIZER" +.circleci/cmake-"$SANITIZER" || (cat /home/builder/c-toxcore/_build/CMakeFiles/CMakeError.log && false) diff --git a/other/docker/circleci/run b/other/docker/circleci/run index 668e0fc865..4b20807f2a 100755 --- a/other/docker/circleci/run +++ b/other/docker/circleci/run @@ -1,6 +1,14 @@ #!/bin/sh +set -eux + SANITIZER="${1:-asan}" +if [ -t 0 ]; then + TTY=true +else + TTY=false +fi + docker build -t toxchat/c-toxcore:circleci other/docker/circleci -docker run --name toxcore-circleci --rm -it -v "$PWD:/c-toxcore" toxchat/c-toxcore:circleci "$SANITIZER" +docker run --name toxcore-circleci --rm --interactive="$TTY" --tty="$TTY" --volume "$PWD:/c-toxcore" toxchat/c-toxcore:circleci "$SANITIZER" diff --git a/other/docker/compcert/compcert.Dockerfile b/other/docker/compcert/compcert.Dockerfile index 567ea786c5..90f16edf6f 100644 --- a/other/docker/compcert/compcert.Dockerfile +++ b/other/docker/compcert/compcert.Dockerfile @@ -13,7 +13,7 @@ COPY --from=sources /src/ /work/ SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN git clone --depth=1 https://github.com/jedisct1/libsodium /work/libsodium +RUN git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium /work/libsodium COPY other/docker/compcert/Makefile /work/ RUN make "-j$(nproc)" RUN ./send_message_test | grep 'tox clients connected' diff --git a/other/docker/esp32/BUILD.bazel b/other/docker/esp32/BUILD.bazel index 5a4009e99f..cee11db69e 100644 --- a/other/docker/esp32/BUILD.bazel +++ b/other/docker/esp32/BUILD.bazel @@ -9,6 +9,7 @@ cc_binary( "main/tox_main.h", ], deps = [ + "//c-toxcore/toxcore:ccompat", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_events", ], diff --git a/other/docker/modules/check b/other/docker/modules/check index 0249efe486..e62be62c8a 100755 --- a/other/docker/modules/check +++ b/other/docker/modules/check @@ -50,6 +50,10 @@ module "//c-toxcore/third_party:cmp" { module "//c-toxcore/toxencryptsave:defines" { header "toxencryptsave/defines.h" } +module "@benchmark" { + textual header "/usr/include/benchmark/benchmark.h" + use std +} module "@com_google_googletest//:gtest" { textual header "/usr/include/gmock/gmock.h" textual header "/usr/include/gtest/gtest.h" @@ -83,9 +87,9 @@ class Context: pass def bzl_exports_files( - self, - srcs: list[str], - visibility: Optional[list[str]] = None, + self, + srcs: list[str], + visibility: Optional[list[str]] = None, ) -> None: pass @@ -110,7 +114,7 @@ class Context: hdrs, } - def bzl_cc_test( + def bzl_cc_binary( self, name: str, srcs: Iterable[str] = tuple(), @@ -161,7 +165,8 @@ def main() -> None: "load": ctx.bzl_load, "exports_files": ctx.bzl_exports_files, "cc_library": ctx.bzl_cc_library, - "cc_test": ctx.bzl_cc_test, + "cc_binary": ctx.bzl_cc_binary, + "cc_test": ctx.bzl_cc_binary, "cc_fuzz_test": ctx.bzl_cc_fuzz_test, "select": ctx.bzl_select, "glob": ctx.bzl_glob, diff --git a/other/docker/modules/modules.Dockerfile b/other/docker/modules/modules.Dockerfile index 5fb03a2504..ca4a7059c8 100644 --- a/other/docker/modules/modules.Dockerfile +++ b/other/docker/modules/modules.Dockerfile @@ -3,6 +3,7 @@ FROM alpine:3.19.0 RUN ["apk", "add", "--no-cache", \ "bash", \ + "benchmark-dev", \ "clang", \ "gtest-dev", \ "libconfig-dev", \ diff --git a/other/docker/perf/Dockerfile b/other/docker/perf/Dockerfile index fe2db29c57..864f29c727 100644 --- a/other/docker/perf/Dockerfile +++ b/other/docker/perf/Dockerfile @@ -3,10 +3,10 @@ FROM alpine:3.14.0 RUN ["apk", "add", "--no-cache", \ "bash", \ "gcc", \ - "linux-headers", \ - "musl-dev", \ "libsodium-dev", \ "libvpx-dev", \ + "linux-headers", \ + "musl-dev", \ "opus-dev", \ "perf"] diff --git a/other/docker/pkgsrc/pkgsrc.Dockerfile b/other/docker/pkgsrc/pkgsrc.Dockerfile index 10fb6a6be2..3483bdfba4 100644 --- a/other/docker/pkgsrc/pkgsrc.Dockerfile +++ b/other/docker/pkgsrc/pkgsrc.Dockerfile @@ -5,6 +5,7 @@ COPY . /work/c-toxcore-0.2.18 RUN ["tar", "zcf", "c-toxcore.tar.gz", "c-toxcore-0.2.18"] WORKDIR /work/pkgsrc/chat/toxcore +RUN ["sed", "-i", "-e", "s/libtoxcore.so.2.18.0/libtoxcore.so.2.20.0/g", "PLIST"] RUN ["bmake", "clean"] RUN ["bmake", "DISTFILES=c-toxcore.tar.gz", "DISTDIR=/work", "NO_CHECKSUM=yes"] RUN ["bmake", "install"] diff --git a/other/docker/windows/get_packages.sh b/other/docker/windows/get_packages.sh index efd81e68c9..54fc155851 100755 --- a/other/docker/windows/get_packages.sh +++ b/other/docker/windows/get_packages.sh @@ -52,7 +52,7 @@ if [ "$SUPPORT_TEST" = "true" ]; then https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources . ./check_sha256.sh - check_sha256 "78b185fabdb323971d13bd329fefc8038e08559aa51c4996de18db0639a51df6" \ + check_sha256 "d965d646defe94b3dfba6d5b4406900ac6c81065428bf9d9303ad7a72ee8d1b8" \ "/etc/apt/keyrings/winehq-archive.key" check_sha256 "8dd8ef66c749d56e798646674c1c185a99b3ed6727ca0fbb5e493951e66c0f9e" \ "/etc/apt/sources.list.d/winehq-bookworm.sources" diff --git a/other/emscripten/Dockerfile b/other/emscripten/Dockerfile index 112b75672b..adfbdba7e3 100644 --- a/other/emscripten/Dockerfile +++ b/other/emscripten/Dockerfile @@ -34,6 +34,7 @@ RUN . "/work/emsdk/emsdk_env.sh" \ && emconfigure ./configure --disable-shared \ --without-pthreads \ --disable-ssp --disable-asm --disable-pie \ + --host x86_64-linux-gnu \ && emmake make install -j8 # Build an unused libsodium binding first so emcc caches all the system diff --git a/other/event_tooling/generate_event_c.cpp b/other/event_tooling/generate_event_c.cpp index de5e52ac8e..9ac3d4856f 100644 --- a/other/event_tooling/generate_event_c.cpp +++ b/other/event_tooling/generate_event_c.cpp @@ -444,7 +444,10 @@ void generate_event_impl(const std::string& event_name, const std::vector> /etc/apt/sources.list && \ @@ -36,12 +48,37 @@ RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main RUN apt-get update && apt-get full-upgrade -y && \ apt-get -y install --no-install-suggests --no-install-recommends \ - gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \ - clang-12 clang-tools-12 libc++1-12 libc++-12-dev \ - libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \ - libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \ - liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \ - libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \ + clang-12 \ + clang-tools-12 \ + g++-10 \ + gcc-10 \ + gcc-10-multilib \ + gcc-10-plugin-dev \ + gcc-multilib \ + gdb \ + lcov \ + libc++-12-dev \ + libc++1-12 \ + libc++abi-12-dev \ + libc++abi1-12 \ + libclang-12-dev \ + libclang-common-12-dev \ + libclang-cpp12 \ + libclang-cpp12-dev \ + libclang1-12 \ + liblld-12 \ + liblld-12-dev \ + liblldb-12 \ + liblldb-12-dev \ + libllvm12 \ + libomp-12-dev \ + libomp5-12 \ + lld-12 \ + lldb-12 \ + llvm-12 \ + llvm-12-dev \ + llvm-12-runtime \ + llvm-12-tools \ && rm -rf /var/lib/apt/lists/* RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0 diff --git a/testing/Makefile.inc b/testing/Makefile.inc index 223ebdcf0c..7d5f24babc 100644 --- a/testing/Makefile.inc +++ b/testing/Makefile.inc @@ -8,10 +8,6 @@ endif noinst_LTLIBRARIES += libmisc_tools.la libmisc_tools_la_SOURCES = ../testing/misc_tools.c ../testing/misc_tools.h -libmisc_tools_la_CFLAGS = $(LIBSODIUM_CFLAGS) - -libmisc_tools_la_LIBADD = $(LIBSODIUM_LDFLAGS) - if BUILD_TESTING noinst_PROGRAMS += Messenger_test diff --git a/testing/Messenger_test.c b/testing/Messenger_test.c index 65ea8a9d2e..18d7347e66 100644 --- a/testing/Messenger_test.c +++ b/testing/Messenger_test.c @@ -118,10 +118,13 @@ int main(int argc, char *argv[]) exit(1); } + // TODO(iphydf): Maybe disable. + const bool dns_enabled = true; + const uint16_t port = net_htons((uint16_t)port_conv); uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]); bool res = dht_bootstrap_from_address(m->dht, argv[argvoffset + 1], - ipv6enabled, port, bootstrap_key); + ipv6enabled, dns_enabled, port, bootstrap_key); free(bootstrap_key); if (!res) { diff --git a/testing/fuzzing/BUILD.bazel b/testing/fuzzing/BUILD.bazel index ce23b792ad..4c9c0a1e31 100644 --- a/testing/fuzzing/BUILD.bazel +++ b/testing/fuzzing/BUILD.bazel @@ -48,6 +48,7 @@ cc_fuzz_test( deps = [ ":fuzz_support", ":fuzz_tox", + "//c-toxcore/toxcore:crypto_core", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", @@ -102,6 +103,7 @@ cc_test( deps = [ ":fuzz_support", ":fuzz_tox", + "//c-toxcore/toxcore:crypto_core", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", @@ -117,6 +119,7 @@ cc_fuzz_test( deps = [ ":fuzz_support", ":fuzz_tox", + "//c-toxcore/toxcore:crypto_core", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox_dispatch", "//c-toxcore/toxcore:tox_events", diff --git a/testing/fuzzing/bootstrap_fuzz_test.cc b/testing/fuzzing/bootstrap_fuzz_test.cc index f25e24319d..4a784f846a 100644 --- a/testing/fuzzing/bootstrap_fuzz_test.cc +++ b/testing/fuzzing/bootstrap_fuzz_test.cc @@ -104,7 +104,6 @@ void TestBootstrap(Fuzz_Data &input) Ptr opts(tox_options_new(nullptr), tox_options_free); assert(opts != nullptr); - tox_options_set_operating_system(opts.get(), sys.sys.get()); tox_options_set_log_callback(opts.get(), [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, @@ -134,8 +133,12 @@ void TestBootstrap(Fuzz_Data &input) tox_options_set_tcp_port(opts.get(), 33445); } + Tox_Options_Testing tox_options_testing; + tox_options_testing.operating_system = sys.sys.get(); + Tox_Err_New error_new; - Tox *tox = tox_new(opts.get(), &error_new); + Tox_Err_New_Testing error_new_testing; + Tox *tox = tox_new_testing(opts.get(), &error_new, &tox_options_testing, &error_new_testing); if (tox == nullptr) { // It might fail, because some I/O happens in tox_new, and the fuzzer @@ -144,6 +147,7 @@ void TestBootstrap(Fuzz_Data &input) } assert(error_new == TOX_ERR_NEW_OK); + assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0}; diff --git a/testing/fuzzing/e2e_fuzz_test.cc b/testing/fuzzing/e2e_fuzz_test.cc index 1be228e040..df4e03c698 100644 --- a/testing/fuzzing/e2e_fuzz_test.cc +++ b/testing/fuzzing/e2e_fuzz_test.cc @@ -138,7 +138,6 @@ void TestEndToEnd(Fuzz_Data &input) Ptr opts(tox_options_new(nullptr), tox_options_free); assert(opts != nullptr); - tox_options_set_operating_system(opts.get(), sys.sys.get()); tox_options_set_local_discovery_enabled(opts.get(), false); tox_options_set_log_callback(opts.get(), @@ -151,8 +150,12 @@ void TestEndToEnd(Fuzz_Data &input) } }); + Tox_Options_Testing tox_options_testing; + tox_options_testing.operating_system = sys.sys.get(); + Tox_Err_New error_new; - Tox *tox = tox_new(opts.get(), &error_new); + Tox_Err_New_Testing error_new_testing; + Tox *tox = tox_new_testing(opts.get(), &error_new, &tox_options_testing, &error_new_testing); if (tox == nullptr) { // It might fail, because some I/O happens in tox_new, and the fuzzer @@ -161,6 +164,7 @@ void TestEndToEnd(Fuzz_Data &input) } assert(error_new == TOX_ERR_NEW_OK); + assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); tox_events_init(tox); diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc index fe760f9958..a98967a905 100644 --- a/testing/fuzzing/fuzz_support.cc +++ b/testing/fuzzing/fuzz_support.cc @@ -4,8 +4,15 @@ #include "fuzz_support.hh" +#ifdef _WIN32 +#include +// Comment line here to avoid reordering by source code formatters. +#include +#include +#else #include #include +#endif #include #include @@ -111,6 +118,7 @@ static constexpr Network_Funcs fuzz_network_funcs = { /* .accept = */ ![](Fuzz_System *self, Socket sock) { return Socket{1337}; }, /* .bind = */ ![](Fuzz_System *self, Socket sock, const Network_Addr *addr) { return 0; }, /* .listen = */ ![](Fuzz_System *self, Socket sock, int backlog) { return 0; }, + /* .connect = */ ![](Fuzz_System *self, Socket sock, const Network_Addr *addr) { return 0; }, /* .recvbuf = */ ![](Fuzz_System *self, Socket sock) { assert(sock.value == 42 || sock.value == 1337); @@ -225,6 +233,7 @@ static constexpr Network_Funcs null_network_funcs = { /* .accept = */ ![](Null_System *self, Socket sock) { return Socket{1337}; }, /* .bind = */ ![](Null_System *self, Socket sock, const Network_Addr *addr) { return 0; }, /* .listen = */ ![](Null_System *self, Socket sock, int backlog) { return 0; }, + /* .connect = */ ![](Null_System *self, Socket sock, const Network_Addr *addr) { return 0; }, /* .recvbuf = */ ![](Null_System *self, Socket sock) { return 0; }, /* .recv = */ ![](Null_System *self, Socket sock, uint8_t *buf, size_t len) { @@ -341,6 +350,7 @@ static constexpr Network_Funcs record_network_funcs = { return 0; }, /* .listen = */ ![](Record_System *self, Socket sock, int backlog) { return 0; }, + /* .connect = */ ![](Record_System *self, Socket sock, const Network_Addr *addr) { return 0; }, /* .recvbuf = */ ![](Record_System *self, Socket sock) { return 0; }, /* .recv = */ ![](Record_System *self, Socket sock, uint8_t *buf, size_t len) { diff --git a/testing/fuzzing/fuzz_support.hh b/testing/fuzzing/fuzz_support.hh index 7f03d341e1..6a370f3dfd 100644 --- a/testing/fuzzing/fuzz_support.hh +++ b/testing/fuzzing/fuzz_support.hh @@ -16,6 +16,7 @@ #include #include "../../toxcore/tox.h" +#include "../../toxcore/tox_private.h" struct Fuzz_Data { static constexpr bool DEBUG = false; diff --git a/testing/fuzzing/protodump.cc b/testing/fuzzing/protodump.cc index 1a3f8c0700..28df05a02a 100644 --- a/testing/fuzzing/protodump.cc +++ b/testing/fuzzing/protodump.cc @@ -195,13 +195,16 @@ void RecordBootstrap(const char *init, const char *bootstrap) }); Tox_Err_New error_new; + Tox_Err_New_Testing error_new_testing; + Tox_Options_Testing tox_options_testing; Record_System sys1(global, 4, "tox1"); // fair dice roll tox_options_set_log_user_data(opts, &sys1); - tox_options_set_operating_system(opts, sys1.sys.get()); - Tox *tox1 = tox_new(opts, &error_new); + tox_options_testing.operating_system = sys1.sys.get(); + Tox *tox1 = tox_new_testing(opts, &error_new, &tox_options_testing, &error_new_testing); assert(tox1 != nullptr); assert(error_new == TOX_ERR_NEW_OK); + assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); std::array address1; tox_self_get_address(tox1, address1.data()); std::array pk1; @@ -211,10 +214,11 @@ void RecordBootstrap(const char *init, const char *bootstrap) Record_System sys2(global, 5, "tox2"); // unfair dice roll tox_options_set_log_user_data(opts, &sys2); - tox_options_set_operating_system(opts, sys2.sys.get()); - Tox *tox2 = tox_new(opts, &error_new); + tox_options_testing.operating_system = sys2.sys.get(); + Tox *tox2 = tox_new_testing(opts, &error_new, &tox_options_testing, &error_new_testing); assert(tox2 != nullptr); assert(error_new == TOX_ERR_NEW_OK); + assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); std::array address2; tox_self_get_address(tox2, address2.data()); std::array pk2; diff --git a/testing/fuzzing/protodump_reduce.cc b/testing/fuzzing/protodump_reduce.cc index ae9676ca31..820a3fc7b8 100644 --- a/testing/fuzzing/protodump_reduce.cc +++ b/testing/fuzzing/protodump_reduce.cc @@ -142,9 +142,11 @@ void TestEndToEnd(Fuzz_Data &input) Ptr opts(tox_options_new(nullptr), tox_options_free); assert(opts != nullptr); - tox_options_set_operating_system(opts.get(), sys.sys.get()); tox_options_set_local_discovery_enabled(opts.get(), false); + Tox_Options_Testing tox_options_testing; + tox_options_testing.operating_system = sys.sys.get(); + tox_options_set_log_callback(opts.get(), [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, const char *message, void *user_data) { @@ -156,7 +158,8 @@ void TestEndToEnd(Fuzz_Data &input) }); Tox_Err_New error_new; - Tox *tox = tox_new(opts.get(), &error_new); + Tox_Err_New_Testing error_new_testing; + Tox *tox = tox_new_testing(opts.get(), &error_new, &tox_options_testing, &error_new_testing); if (tox == nullptr) { // It might fail, because some I/O happens in tox_new, and the fuzzer @@ -165,6 +168,7 @@ void TestEndToEnd(Fuzz_Data &input) } assert(error_new == TOX_ERR_NEW_OK); + assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); tox_events_init(tox); diff --git a/testing/fuzzing/toxsave_fuzz_test.cc b/testing/fuzzing/toxsave_fuzz_test.cc index 2cb134cbc1..f48c2bf013 100644 --- a/testing/fuzzing/toxsave_fuzz_test.cc +++ b/testing/fuzzing/toxsave_fuzz_test.cc @@ -20,14 +20,15 @@ void TestSaveDataLoading(Fuzz_Data &input) const size_t savedata_size = input.size(); CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size); - Null_System sys; - tox_options_set_operating_system(tox_options, sys.sys.get()); - // pass test data to Tox tox_options_set_savedata_data(tox_options, savedata, savedata_size); tox_options_set_savedata_type(tox_options, TOX_SAVEDATA_TYPE_TOX_SAVE); - Tox *tox = tox_new(tox_options, nullptr); + Tox_Options_Testing tox_options_testing; + Null_System sys; + tox_options_testing.operating_system = sys.sys.get(); + + Tox *tox = tox_new_testing(tox_options, nullptr, &tox_options_testing, nullptr); tox_options_free(tox_options); if (tox == nullptr) { // Tox save was invalid, we're finished here diff --git a/testing/misc_tools.c b/testing/misc_tools.c index a2b950c1da..6352f4716e 100644 --- a/testing/misc_tools.c +++ b/testing/misc_tools.c @@ -20,8 +20,6 @@ #include #include -#include - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) #include #else @@ -137,60 +135,3 @@ int cmdline_parsefor_ipv46(int argc, char **argv, bool *ipv6enabled) return argvoffset; } - -static const char *test_rng_name(void) -{ - return "test_rng"; -} - -static uint32_t rng_state; - -static uint32_t test_rng_random(void) -{ - rng_state = 2624534371 * rng_state + 1; - return rng_state; -} - -static void test_rng_buf(void *const buf, const size_t size) -{ - uint8_t *p = (uint8_t *)buf; - uint32_t r = 0; - - for (size_t i = 0; i < size; i++) { - if ((i % 4) == 0) { - r = test_rng_random(); - } - - *p = (r >> ((i % 4) * 8)) & 0xff; - ++p; - } -} - -static uint32_t test_rng_uniform(const uint32_t upper_bound) -{ - // XXX: Not uniform! But that's ok for testing purposes. - return test_rng_random() % upper_bound; -} - -static void test_rng_stir(void) { } -static int test_rng_close(void) -{ - return 0; -} - -static randombytes_implementation test_rng = { - test_rng_name, - test_rng_random, - test_rng_stir, - test_rng_uniform, - test_rng_buf, - test_rng_close -}; - -/* Simple insecure PRNG for testing purposes */ -int use_test_rng(uint32_t seed) -{ - rng_state = seed; - - return randombytes_set_implementation(&test_rng); -} diff --git a/third_party/cmp b/third_party/cmp index 643e6a62d4..52bfcfa17d 160000 --- a/third_party/cmp +++ b/third_party/cmp @@ -1 +1 @@ -Subproject commit 643e6a62d4eb0ec2277de269cda33da02cba2756 +Subproject commit 52bfcfa17d2eb4322da2037ad625f5575129cece diff --git a/toxav/BUILD.bazel b/toxav/BUILD.bazel index f9a669e15d..90fb40d716 100644 --- a/toxav/BUILD.bazel +++ b/toxav/BUILD.bazel @@ -41,125 +41,30 @@ cc_library( deps = ["//c-toxcore/toxcore:ccompat"], ) -cc_library( - name = "bwcontroller", - srcs = ["bwcontroller.c"], - hdrs = ["bwcontroller.h"], - deps = [ - ":ring_buffer", - "//c-toxcore/toxcore", - "//c-toxcore/toxcore:Messenger", - "//c-toxcore/toxcore:ccompat", - "//c-toxcore/toxcore:logger", - "//c-toxcore/toxcore:mono_time", - "//c-toxcore/toxcore:tox", - "//c-toxcore/toxcore:util", - ], -) - -cc_library( - name = "rtp", - srcs = ["rtp.c"], - hdrs = ["rtp.h"], - deps = [ - ":bwcontroller", - "//c-toxcore/toxcore:Messenger", - "//c-toxcore/toxcore:ccompat", - "//c-toxcore/toxcore:logger", - "//c-toxcore/toxcore:mono_time", - "//c-toxcore/toxcore:tox", - "//c-toxcore/toxcore:util", - ], -) - -cc_test( - name = "rtp_test", - size = "small", - srcs = ["rtp_test.cc"], - deps = [ - ":rtp", - "//c-toxcore/toxcore:crypto_core", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "audio", - srcs = ["audio.c"], - hdrs = ["audio.h"], - deps = [ - ":public_api", - ":rtp", - "//c-toxcore/toxcore:ccompat", - "//c-toxcore/toxcore:logger", - "//c-toxcore/toxcore:mono_time", - "//c-toxcore/toxcore:util", - "@opus", - ], -) - -cc_library( - name = "video", - srcs = [ - "msi.c", - "video.c", - ], - hdrs = [ - "msi.h", - "video.h", - ], - deps = [ - ":audio", - ":public_api", - ":ring_buffer", - ":rtp", - "//c-toxcore/toxcore:Messenger", - "//c-toxcore/toxcore:ccompat", - "//c-toxcore/toxcore:logger", - "//c-toxcore/toxcore:mono_time", - "//c-toxcore/toxcore:network", - "//c-toxcore/toxcore:util", - "@libvpx", - ], -) - -cc_library( - name = "groupav", - srcs = ["groupav.c"], - hdrs = ["groupav.h"], - deps = [ - "//c-toxcore/toxcore", - "//c-toxcore/toxcore:ccompat", - "//c-toxcore/toxcore:group", - "//c-toxcore/toxcore:logger", - "//c-toxcore/toxcore:mono_time", - "//c-toxcore/toxcore:tox", - "//c-toxcore/toxcore:util", - "@opus", - ], -) - cc_library( name = "toxav", - srcs = [ - "toxav.c", - "toxav_old.c", - ], - hdrs = [ - "toxav.h", - ], + srcs = glob( + [ + "*.c", + "*.h", + ], + exclude = ["toxav.h"], + ), + hdrs = ["toxav.h"], visibility = ["//c-toxcore:__subpackages__"], deps = [ - ":groupav", - ":rtp", - ":video", "//c-toxcore/toxcore:Messenger", "//c-toxcore/toxcore:ccompat", + "//c-toxcore/toxcore:group", "//c-toxcore/toxcore:logger", "//c-toxcore/toxcore:mono_time", + "//c-toxcore/toxcore:net_crypto", + "//c-toxcore/toxcore:network", "//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:util", + "@libsodium", + "@libvpx", + "@opus", ], ) diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index a8465a2f66..6d34135f3c 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc @@ -19,6 +19,7 @@ libtoxav_la_SOURCES = ../toxav/rtp.h \ ../toxav/ring_buffer.h \ ../toxav/ring_buffer.c \ ../toxav/toxav.h \ + ../toxav/toxav_hacks.h \ ../toxav/toxav.c \ ../toxav/toxav_old.c diff --git a/toxav/audio.c b/toxav/audio.c index 2cbc02d20a..ab11cc0d6b 100644 --- a/toxav/audio.c +++ b/toxav/audio.c @@ -13,6 +13,7 @@ #include "../toxcore/ccompat.h" #include "../toxcore/logger.h" #include "../toxcore/mono_time.h" +#include "../toxcore/network.h" static struct JitterBuffer *jbuf_new(uint32_t capacity); static void jbuf_clear(struct JitterBuffer *q); @@ -25,6 +26,8 @@ static bool reconfigure_audio_encoder(const Logger *log, OpusEncoder **e, uint32 uint8_t new_ch, uint32_t *old_br, uint32_t *old_sr, uint8_t *old_ch); static bool reconfigure_audio_decoder(ACSession *ac, uint32_t sampling_rate, uint8_t channels); + + ACSession *ac_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number, toxav_audio_receive_frame_cb *cb, void *cb_data) { @@ -150,9 +153,9 @@ void ac_iterate(ACSession *ac) ac->lp_channel_count = opus_packet_get_nb_channels(msg->data + 4); - /* NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa, - * it didn't work quite well. - */ + /** NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa, + * it didn't work quite well. + */ if (!reconfigure_audio_decoder(ac, ac->lp_sampling_rate, ac->lp_channel_count)) { LOGGER_WARNING(ac->log, "Failed to reconfigure decoder!"); free(msg); @@ -273,6 +276,7 @@ static struct JitterBuffer *jbuf_new(uint32_t capacity) q->capacity = capacity; return q; } + static void jbuf_clear(struct JitterBuffer *q) { while (q->bottom != q->top) { @@ -281,6 +285,7 @@ static void jbuf_clear(struct JitterBuffer *q) ++q->bottom; } } + static void jbuf_free(struct JitterBuffer *q) { if (q == nullptr) { @@ -291,6 +296,11 @@ static void jbuf_free(struct JitterBuffer *q) free(q->queue); free(q); } + +/* + * if -1 is returned the RTPMessage m needs to be free'd by the caller + * if 0 is returned the RTPMessage m is stored in the ringbuffer and must NOT be freed by the caller + */ static int jbuf_write(const Logger *log, struct JitterBuffer *q, struct RTPMessage *m) { const uint16_t sequnum = m->header.sequnum; @@ -319,6 +329,7 @@ static int jbuf_write(const Logger *log, struct JitterBuffer *q, struct RTPMessa return 0; } + static struct RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success) { if (q->top == q->bottom) { @@ -377,6 +388,21 @@ static OpusEncoder *create_audio_encoder(const Logger *log, uint32_t bit_rate, u goto FAILURE; } + /* + * The libopus library defaults to VBR, which is unsafe in any VoIP environment + * (see for example doi:10.1109/SP.2011.34). Switching to CBR very slightly + * decreases audio quality at lower bitrates. + * + * Parameters: + * `[in]` `x` `opus_int32`: Whether to use VBR mode, 1 (VBR) is default + */ + status = opus_encoder_ctl(rc, OPUS_SET_VBR(0)); + + if (status != OPUS_OK) { + LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status)); + goto FAILURE; + } + /* * Configures the encoder's use of inband forward error correction. * Note: diff --git a/toxav/bwcontroller.c b/toxav/bwcontroller.c index e9ceb96b5a..8dacc92bb0 100644 --- a/toxav/bwcontroller.c +++ b/toxav/bwcontroller.c @@ -10,12 +10,16 @@ #include #include "ring_buffer.h" +#include "toxav_hacks.h" #include "../toxcore/ccompat.h" #include "../toxcore/logger.h" #include "../toxcore/mono_time.h" +#include "../toxcore/network.h" +#include "../toxcore/tox_private.h" #include "../toxcore/util.h" + #define BWC_PACKET_ID 196 #define BWC_SEND_INTERVAL_MS 950 // 0.95s #define BWC_AVG_PKT_COUNT 20 @@ -38,9 +42,8 @@ typedef struct BWCRcvPkt { struct BWController { m_cb *mcb; void *mcb_user_data; - - Messenger *m; Tox *tox; + const Logger *log; uint32_t friend_number; BWCCycle cycle; @@ -49,6 +52,7 @@ struct BWController { uint32_t packet_loss_counted_cycles; Mono_Time *bwc_mono_time; + bool bwc_receive_active; /* if this is set to false then incoming bwc packets will not be processed by bwc_handle_data() */ }; struct BWCMessage { @@ -56,11 +60,11 @@ struct BWCMessage { uint32_t recv; }; -static int bwc_handle_data(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object); -static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length); +static void bwc_handle_data(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, void *user_data); static void send_update(BWController *bwc); -BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data, + +BWController *bwc_new(const Logger *log, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data, Mono_Time *bwc_mono_time) { BWController *retu = (BWController *)calloc(1, sizeof(BWController)); @@ -69,16 +73,18 @@ BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, return nullptr; } - LOGGER_DEBUG(m->log, "Creating bandwidth controller"); + LOGGER_DEBUG(log, "Creating bandwidth controller"); + retu->mcb = mcb; retu->mcb_user_data = mcb_user_data; - retu->m = m; retu->friend_number = friendnumber; retu->bwc_mono_time = bwc_mono_time; const uint64_t now = current_time_monotonic(bwc_mono_time); retu->cycle.last_sent_timestamp = now; retu->cycle.last_refresh_timestamp = now; retu->tox = tox; + retu->log = log; + retu->bwc_receive_active = true; retu->rcvpkt.rb = rb_new(BWC_AVG_PKT_COUNT); retu->cycle.lost = 0; retu->cycle.recv = 0; @@ -89,7 +95,6 @@ BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, rb_write(retu->rcvpkt.rb, &retu->rcvpkt.packet_length_array[i]); } - m_callback_rtp_packet(m, friendnumber, BWC_PACKET_ID, bwc_handle_data, retu); return retu; } @@ -99,7 +104,6 @@ void bwc_kill(BWController *bwc) return; } - m_callback_rtp_packet(bwc->m, bwc->friend_number, BWC_PACKET_ID, nullptr, nullptr); rb_kill(bwc->rcvpkt.rb); free(bwc); } @@ -111,7 +115,7 @@ void bwc_add_lost(BWController *bwc, uint32_t bytes_lost) } if (bytes_lost > 0) { - LOGGER_DEBUG(bwc->m->log, "BWC lost(1): %d", (int)bytes_lost); + LOGGER_DEBUG(bwc->log, "BWC lost(1): %d", (int)bytes_lost); bwc->cycle.lost += bytes_lost; send_update(bwc); } @@ -135,7 +139,7 @@ static void send_update(BWController *bwc) bwc->packet_loss_counted_cycles = 0; if (bwc->cycle.lost != 0) { - LOGGER_DEBUG(bwc->m->log, "%p Sent update rcv: %u lost: %u percent: %f %%", + LOGGER_DEBUG(bwc->log, "%p Sent update rcv: %u lost: %u percent: %f %%", (void *)bwc, bwc->cycle.recv, bwc->cycle.lost, ((double)bwc->cycle.lost / (bwc->cycle.recv + bwc->cycle.lost)) * 100.0); uint8_t bwc_packet[sizeof(struct BWCMessage) + 1]; @@ -148,13 +152,11 @@ static void send_update(BWController *bwc) offset += net_pack_u32(bwc_packet + offset, bwc->cycle.recv); assert(offset == sizeof(bwc_packet)); - if (bwc_send_custom_lossy_packet(bwc->tox, bwc->friend_number, bwc_packet, sizeof(bwc_packet)) == -1) { - char *netstrerror = net_new_strerror(net_error()); - char *stdstrerror = net_new_strerror(errno); - LOGGER_WARNING(bwc->m->log, "BWC send failed (len: %u)! std error: %s, net error %s", - (unsigned)sizeof(bwc_packet), stdstrerror, netstrerror); - net_kill_strerror(stdstrerror); - net_kill_strerror(netstrerror); + Tox_Err_Friend_Custom_Packet error; + tox_friend_send_lossy_packet(bwc->tox, bwc->friend_number, bwc_packet, sizeof(bwc_packet), &error); + + if (error != TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { + LOGGER_WARNING(bwc->log, "BWC send failed: %d", error); } } @@ -166,11 +168,11 @@ static void send_update(BWController *bwc) static int on_update(BWController *bwc, const struct BWCMessage *msg) { - LOGGER_DEBUG(bwc->m->log, "%p Got update from peer", (void *)bwc); + LOGGER_DEBUG(bwc->log, "%p Got update from peer", (void *)bwc); /* Peers sent update too soon */ if (bwc->cycle.last_recv_timestamp + BWC_SEND_INTERVAL_MS > current_time_monotonic(bwc->bwc_mono_time)) { - LOGGER_INFO(bwc->m->log, "%p Rejecting extra update", (void *)bwc); + LOGGER_INFO(bwc->log, "%p Rejecting extra update", (void *)bwc); return -1; } @@ -180,8 +182,8 @@ static int on_update(BWController *bwc, const struct BWCMessage *msg) if (lost != 0 && bwc->mcb != nullptr) { const uint32_t recv = msg->recv; - LOGGER_DEBUG(bwc->m->log, "recved: %u lost: %u percentage: %f %%", recv, lost, - ((double)lost / (recv + lost)) * 100.0); + LOGGER_DEBUG(bwc->log, "recved: %u lost: %u percentage: %f %%", recv, lost, + ((double) lost / (recv + lost)) * 100.0); bwc->mcb(bwc, bwc->friend_number, (float)lost / (recv + lost), bwc->mcb_user_data); @@ -190,28 +192,41 @@ static int on_update(BWController *bwc, const struct BWCMessage *msg) return 0; } -/* - * return -1 on failure, 0 on success - * - */ -static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length) +static void bwc_handle_data(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, void *user_data) { - Tox_Err_Friend_Custom_Packet error; - tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error); + /* get BWController object from Tox and friend number */ + ToxAV *toxav = (ToxAV *)tox_get_av_object(tox); - if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { - return 0; + if (toxav == nullptr) { + // LOGGER_ERROR(log, "Could not get ToxAV object from Tox"); + return; } - return -1; -} - -static int bwc_handle_data(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object) -{ - BWController *bwc = (BWController *)object; + const Logger *log = toxav_get_logger(toxav); if (length - 1 != sizeof(struct BWCMessage)) { - return -1; + LOGGER_ERROR(log, "Got BWCMessage of insufficient size."); + return; + } + + const ToxAVCall *call = call_get(toxav, friend_number); + + if (call == nullptr) { + LOGGER_ERROR(log, "Could not get ToxAVCall object from ToxAV."); + return; + } + + /* get Call object from Tox and friend number */ + BWController *bwc = bwc_controller_get(call); + + if (bwc == nullptr) { + LOGGER_WARNING(log, "No session!"); + return; + } + + if (!bwc->bwc_receive_active) { + LOGGER_WARNING(log, "receiving not allowed!"); + return; } size_t offset = 1; // Ignore packet id. @@ -220,5 +235,15 @@ static int bwc_handle_data(Messenger *m, uint32_t friend_number, const uint8_t * offset += net_unpack_u32(data + offset, &msg.recv); assert(offset == length); - return on_update(bwc, &msg); + on_update(bwc, &msg); +} + +void bwc_allow_receiving(Tox *tox) +{ + tox_callback_friend_lossy_packet_per_pktid(tox, bwc_handle_data, BWC_PACKET_ID); +} + +void bwc_stop_receiving(Tox *tox) +{ + tox_callback_friend_lossy_packet_per_pktid(tox, nullptr, BWC_PACKET_ID); } diff --git a/toxav/bwcontroller.h b/toxav/bwcontroller.h index 53931c030b..0a8f618bc0 100644 --- a/toxav/bwcontroller.h +++ b/toxav/bwcontroller.h @@ -5,19 +5,24 @@ #ifndef C_TOXCORE_TOXAV_BWCONTROLLER_H #define C_TOXCORE_TOXAV_BWCONTROLLER_H -#include "../toxcore/Messenger.h" +#include + +#include "../toxcore/logger.h" +#include "../toxcore/mono_time.h" #include "../toxcore/tox.h" typedef struct BWController BWController; typedef void m_cb(BWController *bwc, uint32_t friend_number, float loss, void *user_data); -BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data, - Mono_Time *bwc_mono_time); +BWController *bwc_new(const Logger *log, Tox *tox, uint32_t friendnumber, + m_cb *mcb, void *mcb_user_data, Mono_Time *bwc_mono_time); void bwc_kill(BWController *bwc); void bwc_add_lost(BWController *bwc, uint32_t bytes_lost); void bwc_add_recv(BWController *bwc, uint32_t recv_bytes); +void bwc_allow_receiving(Tox *tox); +void bwc_stop_receiving(Tox *tox); #endif /* C_TOXCORE_TOXAV_BWCONTROLLER_H */ diff --git a/toxav/groupav.c b/toxav/groupav.c index 63dd569df6..14ca9bb293 100644 --- a/toxav/groupav.c +++ b/toxav/groupav.c @@ -476,7 +476,7 @@ int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t return -1; } - for (uint32_t i = 0; i < numpeers; ++i) { + for (uint32_t i = 0; i < (uint32_t)numpeers; ++i) { group_av_peer_new(group_av, conference_number, i); } @@ -508,7 +508,7 @@ int groupchat_disable_av(const Group_Chats *g_c, uint32_t conference_number) return -1; } - for (uint32_t i = 0; i < numpeers; ++i) { + for (uint32_t i = 0; i < (uint32_t)numpeers; ++i) { group_av_peer_delete(group_av, conference_number, group_peer_get_object(g_c, conference_number, i)); group_peer_set_object(g_c, conference_number, i, nullptr); } diff --git a/toxav/msi.c b/toxav/msi.c index 1b375410b2..5173621361 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -9,8 +9,13 @@ #include #include +#include "toxav_hacks.h" + #include "../toxcore/ccompat.h" #include "../toxcore/logger.h" +#include "../toxcore/net_crypto.h" +#include "../toxcore/tox.h" +#include "../toxcore/tox_private.h" #include "../toxcore/util.h" #define MSI_MAXMSG_SIZE 256 @@ -55,20 +60,20 @@ typedef struct MSIMessage { } MSIMessage; static void msg_init(MSIMessage *dest, MSIRequest request); +static void kill_call(const Logger *log, MSICall *call); static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint16_t length); static uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const uint8_t *value, uint8_t value_len, uint16_t *length); -static int send_message(const Messenger *m, uint32_t friend_number, const MSIMessage *msg); -static int send_error(const Messenger *m, uint32_t friend_number, MSIError error); -static bool invoke_callback(MSICall *call, MSICallbackID cb); +static int send_message(const Logger *log, Tox *tox, uint32_t friend_number, const MSIMessage *msg); +static int send_error(const Logger *log, Tox *tox, uint32_t friend_number, MSIError error); static MSICall *get_call(MSISession *session, uint32_t friend_number); static MSICall *new_call(MSISession *session, uint32_t friend_number); -static void kill_call(MSICall *call); -static void on_peer_status(Messenger *m, uint32_t friend_number, bool is_online, void *user_data); -static void handle_init(MSICall *call, const MSIMessage *msg); -static void handle_push(MSICall *call, const MSIMessage *msg); -static void handle_pop(MSICall *call, const MSIMessage *msg); -static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *user_data); +static bool invoke_callback(const Logger *log, MSICall *call, MSICallbackID cb); +static void handle_init(const Logger *log, MSICall *call, const MSIMessage *msg); +static void handle_push(const Logger *log, MSICall *call, const MSIMessage *msg); +static void handle_pop(const Logger *log, MSICall *call, const MSIMessage *msg); +static void handle_msi_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + void *user_data); /* * Public functions @@ -99,43 +104,43 @@ void msi_callback_capabilities(MSISession *session, msi_action_cb *callback) session->capabilities_callback = callback; } -MSISession *msi_new(Messenger *m) +MSISession *msi_new(const Logger *log, Tox *tox) { - if (m == nullptr) { + if (tox == nullptr) { return nullptr; } MSISession *retu = (MSISession *)calloc(1, sizeof(MSISession)); if (retu == nullptr) { - LOGGER_ERROR(m->log, "Allocation failed! Program might misbehave!"); + LOGGER_ERROR(log, "Allocation failed! Program might misbehave!"); return nullptr; } if (create_recursive_mutex(retu->mutex) != 0) { - LOGGER_ERROR(m->log, "Failed to init mutex! Program might misbehave"); + LOGGER_ERROR(log, "Failed to init mutex! Program might misbehave"); free(retu); return nullptr; } - retu->messenger = m; - - m_callback_msi_packet(m, handle_msi_packet, retu); + retu->tox = tox; - /* This is called when remote terminates session */ - m_callback_connectionstatus_internal_av(m, on_peer_status, retu); + // register callback + tox_callback_friend_lossless_packet_per_pktid(tox, handle_msi_packet, PACKET_ID_MSI); - LOGGER_DEBUG(m->log, "New msi session: %p ", (void *)retu); + LOGGER_DEBUG(log, "New msi session: %p ", (void *)retu); return retu; } -int msi_kill(MSISession *session, const Logger *log) + +int msi_kill(const Logger *log, Tox *tox, MSISession *session) { if (session == nullptr) { LOGGER_ERROR(log, "Tried to terminate non-existing session"); return -1; } - m_callback_msi_packet(session->messenger, nullptr, nullptr); + // UN-register callback + tox_callback_friend_lossless_packet_per_pktid(tox, nullptr, PACKET_ID_MSI); if (pthread_mutex_trylock(session->mutex) != 0) { LOGGER_ERROR(log, "Failed to acquire lock on msi mutex"); @@ -149,10 +154,10 @@ int msi_kill(MSISession *session, const Logger *log) MSICall *it = get_call(session, session->calls_head); while (it != nullptr) { - send_message(session->messenger, it->friend_number, &msg); + send_message(log, session->tox, it->friend_number, &msg); MSICall *temp_it = it; it = it->next; - kill_call(temp_it); /* This will eventually free session->calls */ + kill_call(log, temp_it); /* This will eventually free session->calls */ } } @@ -163,21 +168,57 @@ int msi_kill(MSISession *session, const Logger *log) free(session); return 0; } -int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities) + +/* + * return true if friend is offline and the call was canceled. + */ +bool check_peer_offline_status(const Logger *log, const Tox *tox, MSISession *session, uint32_t friend_number) +{ + if (tox == nullptr || session == nullptr) { + return false; + } + + Tox_Err_Friend_Query f_con_query_error; + const Tox_Connection f_con_status = tox_friend_get_connection_status(tox, friend_number, &f_con_query_error); + + if (f_con_status == TOX_CONNECTION_NONE) { + /* Friend is now offline */ + LOGGER_DEBUG(log, "Friend %d is now offline", friend_number); + + pthread_mutex_lock(session->mutex); + MSICall *call = get_call(session, friend_number); + + if (call == nullptr) { + pthread_mutex_unlock(session->mutex); + return true; + } + + invoke_callback(log, call, MSI_ON_PEERTIMEOUT); /* Failure is ignored */ + kill_call(log, call); + pthread_mutex_unlock(session->mutex); + return true; + } + + return false; +} + +int msi_invite(const Logger *log, MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities) { + LOGGER_DEBUG(log, "msi_invite:session:%p", (void *)session); + if (session == nullptr) { return -1; } - LOGGER_DEBUG(session->messenger->log, "Session: %p Inviting friend: %u", (void *)session, friend_number); + LOGGER_DEBUG(log, "Session: %p Inviting friend: %u", (void *)session, friend_number); if (pthread_mutex_trylock(session->mutex) != 0) { - LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex"); + LOGGER_ERROR(log, "Failed to acquire lock on msi mutex"); return -1; } if (get_call(session, friend_number) != nullptr) { - LOGGER_ERROR(session->messenger->log, "Already in a call"); + LOGGER_ERROR(log, "Already in a call"); pthread_mutex_unlock(session->mutex); return -1; } @@ -197,17 +238,18 @@ int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint msg.capabilities.exists = true; msg.capabilities.value = capabilities; - send_message(temp->session->messenger, temp->friend_number, &msg); + send_message(log, temp->session->tox, temp->friend_number, &msg); temp->state = MSI_CALL_REQUESTING; *call = temp; - LOGGER_DEBUG(session->messenger->log, "Invite sent"); + LOGGER_DEBUG(log, "Invite sent"); pthread_mutex_unlock(session->mutex); return 0; } -int msi_hangup(MSICall *call) + +int msi_hangup(const Logger *log, MSICall *call) { if (call == nullptr || call->session == nullptr) { return -1; @@ -215,16 +257,16 @@ int msi_hangup(MSICall *call) MSISession *session = call->session; - LOGGER_DEBUG(session->messenger->log, "Session: %p Hanging up call with friend: %u", (void *)call->session, + LOGGER_DEBUG(log, "Session: %p Hanging up call with friend: %u", (void *)call->session, call->friend_number); if (pthread_mutex_trylock(session->mutex) != 0) { - LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex"); + LOGGER_ERROR(log, "Failed to acquire lock on msi mutex"); return -1; } if (call->state == MSI_CALL_INACTIVE) { - LOGGER_ERROR(session->messenger->log, "Call is in invalid state!"); + LOGGER_ERROR(log, "Call is in invalid state!"); pthread_mutex_unlock(session->mutex); return -1; } @@ -232,13 +274,14 @@ int msi_hangup(MSICall *call) MSIMessage msg; msg_init(&msg, REQU_POP); - send_message(session->messenger, call->friend_number, &msg); + send_message(log, session->tox, call->friend_number, &msg); - kill_call(call); + kill_call(log, call); pthread_mutex_unlock(session->mutex); return 0; } -int msi_answer(MSICall *call, uint8_t capabilities) + +int msi_answer(const Logger *log, MSICall *call, uint8_t capabilities) { if (call == nullptr || call->session == nullptr) { return -1; @@ -246,18 +289,18 @@ int msi_answer(MSICall *call, uint8_t capabilities) MSISession *session = call->session; - LOGGER_DEBUG(session->messenger->log, "Session: %p Answering call from: %u", (void *)call->session, + LOGGER_DEBUG(log, "Session: %p Answering call from: %u", (void *)call->session, call->friend_number); if (pthread_mutex_trylock(session->mutex) != 0) { - LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex"); + LOGGER_ERROR(log, "Failed to acquire lock on msi mutex"); return -1; } if (call->state != MSI_CALL_REQUESTED) { /* Though sending in invalid state will not cause anything weird * Its better to not do it like a maniac */ - LOGGER_ERROR(session->messenger->log, "Call is in invalid state!"); + LOGGER_ERROR(log, "Call is in invalid state!"); pthread_mutex_unlock(session->mutex); return -1; } @@ -270,14 +313,15 @@ int msi_answer(MSICall *call, uint8_t capabilities) msg.capabilities.exists = true; msg.capabilities.value = capabilities; - send_message(session->messenger, call->friend_number, &msg); + send_message(log, session->tox, call->friend_number, &msg); call->state = MSI_CALL_ACTIVE; pthread_mutex_unlock(session->mutex); return 0; } -int msi_change_capabilities(MSICall *call, uint8_t capabilities) + +int msi_change_capabilities(const Logger *log, MSICall *call, uint8_t capabilities) { if (call == nullptr || call->session == nullptr) { return -1; @@ -285,16 +329,16 @@ int msi_change_capabilities(MSICall *call, uint8_t capabilities) MSISession *session = call->session; - LOGGER_DEBUG(session->messenger->log, "Session: %p Trying to change capabilities to friend %u", (void *)call->session, + LOGGER_DEBUG(log, "Session: %p Trying to change capabilities to friend %u", (void *)call->session, call->friend_number); if (pthread_mutex_trylock(session->mutex) != 0) { - LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex"); + LOGGER_ERROR(log, "Failed to acquire lock on msi mutex"); return -1; } if (call->state != MSI_CALL_ACTIVE) { - LOGGER_ERROR(session->messenger->log, "Call is in invalid state!"); + LOGGER_ERROR(log, "Call is in invalid state!"); pthread_mutex_unlock(session->mutex); return -1; } @@ -307,7 +351,7 @@ int msi_change_capabilities(MSICall *call, uint8_t capabilities) msg.capabilities.exists = true; msg.capabilities.value = capabilities; - send_message(call->session->messenger, call->friend_number, &msg); + send_message(log, call->session->tox, call->friend_number, &msg); pthread_mutex_unlock(session->mutex); return 0; @@ -351,10 +395,51 @@ static bool check_enum_high(const Logger *log, const uint8_t *bytes, uint8_t enu return true; } +static const uint8_t *msg_parse_one(const Logger *log, MSIMessage *dest, const uint8_t *it, int *size_constraint) +{ + switch (*it) { + case ID_REQUEST: { + if (!check_size(log, it, size_constraint, 1) || + !check_enum_high(log, it, REQU_POP)) { + return nullptr; + } + + dest->request.value = (MSIRequest)it[2]; + dest->request.exists = true; + return it + 3; + } + + case ID_ERROR: { + if (!check_size(log, it, size_constraint, 1) || + !check_enum_high(log, it, MSI_E_UNDISCLOSED)) { + return nullptr; + } + + dest->error.value = (MSIError)it[2]; + dest->error.exists = true; + return it + 3; + } + + case ID_CAPABILITIES: { + if (!check_size(log, it, size_constraint, 1)) { + return nullptr; + } + + dest->capabilities.value = it[2]; + dest->capabilities.exists = true; + return it + 3; + } + + default: { + LOGGER_ERROR(log, "Invalid id byte: %d", *it); + return nullptr; + } + } +} + static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint16_t length) { /* Parse raw data received from socket into MSIMessage struct */ - assert(dest != nullptr); if (length == 0 || data[length - 1] != 0) { /* End byte must have value 0 */ @@ -368,46 +453,10 @@ static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data int size_constraint = length; while (*it != 0) {/* until end byte is hit */ - switch (*it) { - case ID_REQUEST: { - if (!check_size(log, it, &size_constraint, 1) || - !check_enum_high(log, it, REQU_POP)) { - return -1; - } - - dest->request.value = (MSIRequest)it[2]; - dest->request.exists = true; - it += 3; - break; - } - - case ID_ERROR: { - if (!check_size(log, it, &size_constraint, 1) || - !check_enum_high(log, it, MSI_E_UNDISCLOSED)) { - return -1; - } - - dest->error.value = (MSIError)it[2]; - dest->error.exists = true; - it += 3; - break; - } - - case ID_CAPABILITIES: { - if (!check_size(log, it, &size_constraint, 1)) { - return -1; - } + it = msg_parse_one(log, dest, it, &size_constraint); - dest->capabilities.value = it[2]; - dest->capabilities.exists = true; - it += 3; - break; - } - - default: { - LOGGER_ERROR(log, "Invalid id byte"); - return -1; - } + if (it == nullptr) { + return -1; } } @@ -418,6 +467,7 @@ static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data return 0; } + static uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const uint8_t *value, uint8_t value_len, uint16_t *length) { @@ -437,11 +487,48 @@ static uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const uint8_ return dest + value_len; /* Set to next position ready to be written */ } -static int send_message(const Messenger *m, uint32_t friend_number, const MSIMessage *msg) + +/* Send an msi packet. + * + * return 1 on success + * return 0 on failure + */ +static int m_msi_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length) { - /* Parse and send message */ - assert(m != nullptr); + // TODO(Zoff): make this better later! ------------------- + /* we need to prepend 1 byte (packet id) to data + * do this without malloc, memcpy and free in the future + */ + const size_t length_new = (size_t)length + 1; + uint8_t *data_new = (uint8_t *)malloc(length_new); + + if (data_new == nullptr) { + return 0; + } + + data_new[0] = PACKET_ID_MSI; + + if (length != 0) { + memcpy(data_new + 1, data, length); + } + + Tox_Err_Friend_Custom_Packet error; + tox_friend_send_lossless_packet(tox, friendnumber, data_new, length_new, &error); + + free(data_new); + + if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { + return 1; + } + + return 0; +} + +static int send_message(const Logger *log, Tox *tox, uint32_t friend_number, const MSIMessage *msg) +{ + assert(tox != nullptr); + /* Parse and send message */ uint8_t parsed[MSI_MAXMSG_SIZE]; uint8_t *it = parsed; @@ -452,7 +539,7 @@ static int send_message(const Messenger *m, uint32_t friend_number, const MSIMes it = msg_parse_header_out(ID_REQUEST, it, &cast, sizeof(cast), &size); } else { - LOGGER_DEBUG(m->log, "Must have request field"); + LOGGER_DEBUG(log, "Must have request field"); return -1; } @@ -468,26 +555,27 @@ static int send_message(const Messenger *m, uint32_t friend_number, const MSIMes } if (it == parsed) { - LOGGER_WARNING(m->log, "Parsing message failed; empty message"); + LOGGER_WARNING(log, "Parsing message failed; empty message"); return -1; } *it = 0; ++size; - if (m_msi_packet(m, friend_number, parsed, size)) { - LOGGER_DEBUG(m->log, "Sent message"); + if (m_msi_packet(tox, friend_number, parsed, size) == 1) { + LOGGER_DEBUG(log, "Sent message"); return 0; } return -1; } -static int send_error(const Messenger *m, uint32_t friend_number, MSIError error) + +static int send_error(const Logger *log, Tox *tox, uint32_t friend_number, MSIError error) { - /* Send error message */ - assert(m != nullptr); + assert(tox != nullptr); - LOGGER_DEBUG(m->log, "Sending error: %d to friend: %d", error, friend_number); + /* Send error message */ + LOGGER_DEBUG(log, "Sending error: %d to friend: %d", error, friend_number); MSIMessage msg; msg_init(&msg, REQU_POP); @@ -495,13 +583,14 @@ static int send_error(const Messenger *m, uint32_t friend_number, MSIError error msg.error.exists = true; msg.error.value = error; - send_message(m, friend_number, &msg); + send_message(log, tox, friend_number, &msg); return 0; } -static int invoke_callback_inner(MSICall *call, MSICallbackID id) + +static int invoke_callback_inner(const Logger *log, MSICall *call, MSICallbackID id) { MSISession *session = call->session; - LOGGER_DEBUG(session->messenger->log, "invoking callback function: %d", id); + LOGGER_DEBUG(log, "invoking callback function: %d", id); switch (id) { case MSI_ON_INVITE: @@ -523,15 +612,16 @@ static int invoke_callback_inner(MSICall *call, MSICallbackID id) return session->capabilities_callback(session->av, call); } - LOGGER_FATAL(session->messenger->log, "invalid callback id: %d", id); + LOGGER_FATAL(log, "invalid callback id: %d", id); return -1; } -static bool invoke_callback(MSICall *call, MSICallbackID cb) + +static bool invoke_callback(const Logger *log, MSICall *call, MSICallbackID cb) { assert(call != nullptr); - if (invoke_callback_inner(call, cb) != 0) { - LOGGER_WARNING(call->session->messenger->log, + if (invoke_callback_inner(log, call, cb) != 0) { + LOGGER_WARNING(log, "Callback state handling failed, sending error"); /* If no callback present or error happened while handling, @@ -546,6 +636,7 @@ static bool invoke_callback(MSICall *call, MSICallbackID cb) return true; } + static MSICall *get_call(MSISession *session, uint32_t friend_number) { assert(session != nullptr); @@ -556,6 +647,7 @@ static MSICall *get_call(MSISession *session, uint32_t friend_number) return session->calls[friend_number]; } + static MSICall *new_call(MSISession *session, uint32_t friend_number) { assert(session != nullptr); @@ -607,7 +699,8 @@ static MSICall *new_call(MSISession *session, uint32_t friend_number) session->calls[friend_number] = rc; return rc; } -static void kill_call(MSICall *call) + +static void kill_call(const Logger *log, MSICall *call) { /* Assume that session mutex is locked */ if (call == nullptr) { @@ -616,7 +709,7 @@ static void kill_call(MSICall *call) MSISession *session = call->session; - LOGGER_DEBUG(session->messenger->log, "Killing call: %p", (void *)call); + LOGGER_DEBUG(log, "Killing call: %p", (void *)call); MSICall *prev = call->prev; MSICall *next = call->next; @@ -648,37 +741,12 @@ static void kill_call(MSICall *call) free(call); session->calls = nullptr; } -static void on_peer_status(Messenger *m, uint32_t friend_number, bool is_online, void *user_data) -{ - MSISession *session = (MSISession *)user_data; - - if (is_online) { - // Friend is online. - return; - } - LOGGER_DEBUG(m->log, "Friend %d is now offline", friend_number); - pthread_mutex_lock(session->mutex); - MSICall *call = get_call(session, friend_number); - - if (call == nullptr) { - pthread_mutex_unlock(session->mutex); - return; - } - - invoke_callback(call, MSI_ON_PEERTIMEOUT); /* Failure is ignored */ - kill_call(call); - pthread_mutex_unlock(session->mutex); -} -static bool try_handle_init(MSICall *call, const MSIMessage *msg) +static bool try_handle_init(const Logger *log, MSICall *call, const MSIMessage *msg) { - assert(call != nullptr); - LOGGER_DEBUG(call->session->messenger->log, - "Session: %p Handling 'init' friend: %d", (void *)call->session, call->friend_number); - if (!msg->capabilities.exists) { - LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'init'", (void *)call->session); + LOGGER_WARNING(log, "Session: %p Invalid capabilities on 'init'", (void *)call->session); call->error = MSI_E_INVALID_MESSAGE; return false; } @@ -689,7 +757,7 @@ static bool try_handle_init(MSICall *call, const MSIMessage *msg) call->peer_capabilities = msg->capabilities.value; call->state = MSI_CALL_REQUESTED; - if (!invoke_callback(call, MSI_ON_INVITE)) { + if (!invoke_callback(log, call, MSI_ON_INVITE)) { return false; } @@ -704,7 +772,7 @@ static bool try_handle_init(MSICall *call, const MSIMessage *msg) * we can automatically answer the re-call. */ - LOGGER_INFO(call->session->messenger->log, "Friend is recalling us"); + LOGGER_INFO(log, "Friend is recalling us"); MSIMessage out_msg; msg_init(&out_msg, REQU_PUSH); @@ -712,7 +780,7 @@ static bool try_handle_init(MSICall *call, const MSIMessage *msg) out_msg.capabilities.exists = true; out_msg.capabilities.value = call->self_capabilities; - send_message(call->session->messenger, call->friend_number, &out_msg); + send_message(log, call->session->tox, call->friend_number, &out_msg); /* If peer changed capabilities during re-call they will * be handled accordingly during the next step @@ -722,7 +790,7 @@ static bool try_handle_init(MSICall *call, const MSIMessage *msg) case MSI_CALL_REQUESTED: // fall-through case MSI_CALL_REQUESTING: { - LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid state on 'init'", (void *)call->session); + LOGGER_WARNING(log, "Session: %p Invalid state on 'init'", (void *)call->session); call->error = MSI_E_INVALID_STATE; return false; } @@ -730,26 +798,28 @@ static bool try_handle_init(MSICall *call, const MSIMessage *msg) return true; } -static void handle_init(MSICall *call, const MSIMessage *msg) + +static void handle_init(const Logger *log, MSICall *call, const MSIMessage *msg) { assert(call != nullptr); - LOGGER_DEBUG(call->session->messenger->log, + LOGGER_DEBUG(log, "Session: %p Handling 'init' friend: %d", (void *)call->session, call->friend_number); - if (!try_handle_init(call, msg)) { - send_error(call->session->messenger, call->friend_number, call->error); - kill_call(call); + if (!try_handle_init(log, call, msg)) { + send_error(log, call->session->tox, call->friend_number, call->error); + kill_call(log, call); } } -static void handle_push(MSICall *call, const MSIMessage *msg) + +static void handle_push(const Logger *log, MSICall *call, const MSIMessage *msg) { assert(call != nullptr); - LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'push' friend: %d", (void *)call->session, + LOGGER_DEBUG(log, "Session: %p Handling 'push' friend: %d", (void *)call->session, call->friend_number); if (!msg->capabilities.exists) { - LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'push'", (void *)call->session); + LOGGER_WARNING(log, "Session: %p Invalid capabilities on 'push'", (void *)call->session); call->error = MSI_E_INVALID_MESSAGE; goto FAILURE; } @@ -757,12 +827,11 @@ static void handle_push(MSICall *call, const MSIMessage *msg) switch (call->state) { case MSI_CALL_ACTIVE: { if (call->peer_capabilities != msg->capabilities.value) { - /* Only act if capabilities changed */ - LOGGER_INFO(call->session->messenger->log, "Friend is changing capabilities to: %u", msg->capabilities.value); + LOGGER_INFO(log, "Friend is changing capabilities to: %u", msg->capabilities.value); call->peer_capabilities = msg->capabilities.value; - if (!invoke_callback(call, MSI_ON_CAPABILITIES)) { + if (!invoke_callback(log, call, MSI_ON_CAPABILITIES)) { goto FAILURE; } } @@ -771,13 +840,13 @@ static void handle_push(MSICall *call, const MSIMessage *msg) } case MSI_CALL_REQUESTING: { - LOGGER_INFO(call->session->messenger->log, "Friend answered our call"); + LOGGER_INFO(log, "Friend answered our call"); /* Call started */ call->peer_capabilities = msg->capabilities.value; call->state = MSI_CALL_ACTIVE; - if (!invoke_callback(call, MSI_ON_START)) { + if (!invoke_callback(log, call, MSI_ON_START)) { goto FAILURE; } @@ -786,8 +855,7 @@ static void handle_push(MSICall *call, const MSIMessage *msg) case MSI_CALL_INACTIVE: // fall-through case MSI_CALL_REQUESTED: { - /* Pushes during initialization state are ignored */ - LOGGER_WARNING(call->session->messenger->log, "Ignoring invalid push"); + LOGGER_WARNING(log, "Ignoring invalid push"); break; } } @@ -795,76 +863,102 @@ static void handle_push(MSICall *call, const MSIMessage *msg) return; FAILURE: - send_error(call->session->messenger, call->friend_number, call->error); - kill_call(call); + send_error(log, call->session->tox, call->friend_number, call->error); + kill_call(log, call); } -static void handle_pop(MSICall *call, const MSIMessage *msg) + +static void handle_pop(const Logger *log, MSICall *call, const MSIMessage *msg) { assert(call != nullptr); - LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'pop', friend id: %d", (void *)call->session, + LOGGER_DEBUG(log, "Session: %p Handling 'pop', friend id: %d", (void *)call->session, call->friend_number); /* callback errors are ignored */ if (msg->error.exists) { - LOGGER_WARNING(call->session->messenger->log, "Friend detected an error: %d", msg->error.value); + LOGGER_WARNING(log, "Friend detected an error: %d", msg->error.value); call->error = msg->error.value; - invoke_callback(call, MSI_ON_ERROR); + invoke_callback(log, call, MSI_ON_ERROR); } else { switch (call->state) { case MSI_CALL_INACTIVE: { - LOGGER_FATAL(call->session->messenger->log, "Handling what should be impossible case"); + LOGGER_FATAL(log, "Handling what should be impossible case"); break; } case MSI_CALL_ACTIVE: { /* Hangup */ - LOGGER_INFO(call->session->messenger->log, "Friend hung up on us"); - invoke_callback(call, MSI_ON_END); + LOGGER_INFO(log, "Friend hung up on us"); + invoke_callback(log, call, MSI_ON_END); break; } case MSI_CALL_REQUESTING: { /* Reject */ - LOGGER_INFO(call->session->messenger->log, "Friend rejected our call"); - invoke_callback(call, MSI_ON_END); + LOGGER_INFO(log, "Friend rejected our call"); + invoke_callback(log, call, MSI_ON_END); break; } case MSI_CALL_REQUESTED: { /* Cancel */ - LOGGER_INFO(call->session->messenger->log, "Friend canceled call invite"); - invoke_callback(call, MSI_ON_END); + LOGGER_INFO(log, "Friend canceled call invite"); + invoke_callback(log, call, MSI_ON_END); break; } } } - kill_call(call); + kill_call(log, call); } -static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *user_data) + +static void handle_msi_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + void *user_data) { - MSISession *session = (MSISession *)user_data; + const ToxAV *toxav = (ToxAV *)tox_get_av_object(tox); + + if (toxav == nullptr) { + return; + } + + const Logger *log = toxav_get_logger(toxav); + + if (length < 2) { + LOGGER_ERROR(log, "MSI packet is less than 2 bytes in size"); + // we need more than the ID byte for MSI messages + return; + } - LOGGER_DEBUG(m->log, "Got msi message"); + const uint16_t payload_length = (uint16_t)(length - 1); + + // Zoff: do not show the first byte, its always "PACKET_ID_MSI" + const uint8_t *data_strip_id_byte = data + 1; + + LOGGER_DEBUG(log, "Got msi message"); + + MSISession *session = tox_av_msi_get(toxav); + + if (session == nullptr) { + return; + } MSIMessage msg; - if (msg_parse_in(m->log, &msg, data, length) == -1) { - LOGGER_WARNING(m->log, "Error parsing message"); - send_error(m, friend_number, MSI_E_INVALID_MESSAGE); + if (msg_parse_in(log, &msg, data_strip_id_byte, payload_length) == -1) { + LOGGER_WARNING(log, "Error parsing message"); + send_error(log, tox, friend_number, MSI_E_INVALID_MESSAGE); return; } - LOGGER_DEBUG(m->log, "Successfully parsed message"); + LOGGER_DEBUG(log, "Successfully parsed message"); pthread_mutex_lock(session->mutex); MSICall *call = get_call(session, friend_number); if (call == nullptr) { if (msg.request.value != REQU_INIT) { - send_error(m, friend_number, MSI_E_STRAY_MESSAGE); + send_error(log, tox, friend_number, MSI_E_STRAY_MESSAGE); pthread_mutex_unlock(session->mutex); return; } @@ -872,7 +966,7 @@ static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_ call = new_call(session, friend_number); if (call == nullptr) { - send_error(m, friend_number, MSI_E_SYSTEM); + send_error(log, tox, friend_number, MSI_E_SYSTEM); pthread_mutex_unlock(session->mutex); return; } @@ -880,17 +974,17 @@ static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_ switch (msg.request.value) { case REQU_INIT: { - handle_init(call, &msg); + handle_init(log, call, &msg); break; } case REQU_PUSH: { - handle_push(call, &msg); + handle_push(log, call, &msg); break; } case REQU_POP: { - handle_pop(call, &msg); /* always kills the call */ + handle_pop(log, call, &msg); /* always kills the call */ break; } } diff --git a/toxav/msi.h b/toxav/msi.h index f034a35c9c..88d01572ff 100644 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -11,7 +11,6 @@ #include "audio.h" #include "video.h" -#include "../toxcore/Messenger.h" #include "../toxcore/logger.h" /** @@ -42,22 +41,22 @@ typedef enum MSICapabilities { * Call state identifiers. */ typedef enum MSICallState { - MSI_CALL_INACTIVE, /* Default */ - MSI_CALL_ACTIVE, - MSI_CALL_REQUESTING, /* when sending call invite */ - MSI_CALL_REQUESTED, /* when getting call invite */ + MSI_CALL_INACTIVE = 0, /* Default */ + MSI_CALL_ACTIVE = 1, + MSI_CALL_REQUESTING = 2, /* when sending call invite */ + MSI_CALL_REQUESTED = 3, /* when getting call invite */ } MSICallState; /** * Callbacks ids that handle the states */ typedef enum MSICallbackID { - MSI_ON_INVITE, /* Incoming call */ - MSI_ON_START, /* Call (RTP transmission) started */ - MSI_ON_END, /* Call that was active ended */ - MSI_ON_ERROR, /* On protocol error */ - MSI_ON_PEERTIMEOUT, /* Peer timed out; stop the call */ - MSI_ON_CAPABILITIES, /* Peer requested capabilities change */ + MSI_ON_INVITE = 0, /* Incoming call */ + MSI_ON_START = 1, /* Call (RTP transmission) started */ + MSI_ON_END = 2, /* Call that was active ended */ + MSI_ON_ERROR = 3, /* On protocol error */ + MSI_ON_PEERTIMEOUT = 4, /* Peer timed out; stop the call */ + MSI_ON_CAPABILITIES = 5, /* Peer requested capabilities change */ } MSICallbackID; /** @@ -96,7 +95,7 @@ typedef struct MSISession { uint32_t calls_head; void *av; - Messenger *messenger; + Tox *tox; pthread_mutex_t mutex[1]; @@ -111,11 +110,11 @@ typedef struct MSISession { /** * Start the control session. */ -MSISession *msi_new(Messenger *m); +MSISession *msi_new(const Logger *log, Tox *tox); /** * Terminate control session. NOTE: all calls will be freed */ -int msi_kill(MSISession *session, const Logger *log); +int msi_kill(const Logger *log, Tox *tox, MSISession *session); /** * Callback setters. */ @@ -128,18 +127,20 @@ void msi_callback_capabilities(MSISession *session, msi_action_cb *callback); /** * Send invite request to friend_number. */ -int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities); +int msi_invite(const Logger *log, MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities); /** * Hangup call. NOTE: `call` will be freed */ -int msi_hangup(MSICall *call); +int msi_hangup(const Logger *log, MSICall *call); /** * Answer call request. */ -int msi_answer(MSICall *call, uint8_t capabilities); +int msi_answer(const Logger *log, MSICall *call, uint8_t capabilities); /** * Change capabilities of the call. */ -int msi_change_capabilities(MSICall *call, uint8_t capabilities); +int msi_change_capabilities(const Logger *log, MSICall *call, uint8_t capabilities); + +bool check_peer_offline_status(const Logger *log, const Tox *tox, MSISession *session, uint32_t friend_number); #endif /* C_TOXCORE_TOXAV_MSI_H */ diff --git a/toxav/rtp.c b/toxav/rtp.c index 8ad4ce670e..32c90009d0 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -9,12 +9,16 @@ #include #include +#include + #include "bwcontroller.h" +#include "toxav_hacks.h" -#include "../toxcore/Messenger.h" #include "../toxcore/ccompat.h" #include "../toxcore/logger.h" #include "../toxcore/mono_time.h" +#include "../toxcore/net_crypto.h" +#include "../toxcore/tox_private.h" #include "../toxcore/util.h" /** @@ -23,30 +27,15 @@ */ #define VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS 15 -/** - * return -1 on failure, 0 on success - * - */ -static int rtp_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length) -{ - Tox_Err_Friend_Custom_Packet error; - tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error); - - if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { - return 0; - } - - return -1; -} - // allocate_len is NOT including header! -static struct RTPMessage *new_message(const struct RTPHeader *header, size_t allocate_len, const uint8_t *data, - uint16_t data_length) +static struct RTPMessage *new_message(const Logger *log, const struct RTPHeader *header, size_t allocate_len, + const uint8_t *data, uint16_t data_length) { assert(allocate_len >= data_length); struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + allocate_len); if (msg == nullptr) { + LOGGER_DEBUG(log, "Could not allocate RTPMessage buffer"); return nullptr; } @@ -241,7 +230,7 @@ static struct RTPMessage *process_frame(const Logger *log, struct RTPWorkBufferL } /** - * @param log A logger. + * @param log A pointer to the Logger object. * @param wkbl The list of in-progress frames, i.e. all the slots. * @param slot_id The slot we want to fill the data into. * @param is_keyframe Whether the data is part of a key frame. @@ -309,7 +298,7 @@ static bool fill_data_into_slot(const Logger *log, struct RTPWorkBufferList *wkb return slot->received_len == header->data_length_full; } -static void update_bwc_values(const Logger *log, RTPSession *session, const struct RTPMessage *msg) +static void update_bwc_values(RTPSession *session, const struct RTPMessage *msg) { if (session->first_packets_counter < DISMISS_FIRST_LOST_VIDEO_PACKET_COUNT) { ++session->first_packets_counter; @@ -319,7 +308,7 @@ static void update_bwc_values(const Logger *log, RTPSession *session, const stru bwc_add_recv(session->bwc, data_length_full); if (received_length_full < data_length_full) { - LOGGER_DEBUG(log, "BWC: full length=%u received length=%d", data_length_full, received_length_full); + LOGGER_DEBUG(session->log, "BWC: full length=%u received length=%d", data_length_full, received_length_full); bwc_add_lost(session->bwc, data_length_full - received_length_full); } } @@ -347,22 +336,16 @@ static void update_bwc_values(const Logger *log, RTPSession *session, const stru * @retval -1 on error. * @retval 0 on success. */ -static int handle_video_packet(RTPSession *session, const struct RTPHeader *header, - const uint8_t *incoming_data, uint16_t incoming_data_length, const Logger *log) +static int handle_video_packet(const Logger *log, RTPSession *session, const struct RTPHeader *header, + const uint8_t *incoming_data, uint16_t incoming_data_length) { // Full frame length in bytes. The frame may be split into multiple packets, // but this value is the complete assembled frame size. const uint32_t full_frame_length = header->data_length_full; - // Current offset in the frame. If this is the first packet of a multipart - // frame or it's not a multipart frame, then this value is 0. - const uint32_t offset = header->offset_full; // without header - // The sender tells us whether this is a key frame. const bool is_keyframe = (header->flags & RTP_KEY_FRAME) != 0; - LOGGER_DEBUG(log, "-- handle_video_packet -- full lens=%u len=%u offset=%u is_keyframe=%s", - (unsigned)incoming_data_length, (unsigned)full_frame_length, (unsigned)offset, is_keyframe ? "K" : "."); LOGGER_DEBUG(log, "wkbl->next_free_entry:003=%d", session->work_buffer_list->next_free_entry); const bool is_multipart = full_frame_length != incoming_data_length; @@ -387,10 +370,13 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head // get_slot just told us it's full, so process_frame must return non-null. assert(m_new != nullptr); - LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]); - update_bwc_values(log, session, m_new); + LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0], + (int)m_new->data[1]); + update_bwc_values(session, m_new); // Pass ownership of m_new to the callback. - session->mcb(session->m->mono_time, session->cs, m_new); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, m_new); // Now we no longer own m_new. m_new = nullptr; @@ -425,9 +411,12 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, slot_id); if (m_new != nullptr) { - LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]); - update_bwc_values(log, session, m_new); - session->mcb(session->m->mono_time, session->cs, m_new); + LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0], + (int)m_new->data[1]); + update_bwc_values(session, m_new); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, m_new); m_new = nullptr; } @@ -436,80 +425,113 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head } /** - * @retval -1 on error. - * @retval 0 on success. + * receive custom lossypackets and process them. they can be incoming audio or video packets */ -static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object) +void handle_rtp_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, void *user_data) { - RTPSession *session = (RTPSession *)object; + ToxAV *toxav = (ToxAV *)tox_get_av_object(tox); - if (session == nullptr || length < RTP_HEADER_SIZE + 1) { - LOGGER_WARNING(m->log, "No session or invalid length of received buffer!"); - return -1; + if (toxav == nullptr) { + // LOGGER_WARNING(log, "ToxAV is NULL!"); + return; + } + + const Logger *log = toxav_get_logger(toxav); + + if (length < RTP_HEADER_SIZE + 1) { + LOGGER_WARNING(log, "Invalid length of received buffer!"); + return; + } + + ToxAVCall *call = call_get(toxav, friend_number); + + if (call == nullptr) { + LOGGER_WARNING(log, "ToxAVCall is NULL!"); + return; + } + + RTPSession *session = rtp_session_get(call, data[0]); + + if (session == nullptr) { + LOGGER_WARNING(log, "No session!"); + return; + } + + if (!session->rtp_receive_active) { + LOGGER_WARNING(log, "receiving not allowed!"); + return; } // Get the packet type. const uint8_t packet_type = data[0]; - ++data; - --length; + const uint8_t *payload = &data[1]; + // TODO(Zoff): is this ok? + const uint16_t payload_size = (uint16_t)length - 1; // Unpack the header. struct RTPHeader header; - rtp_header_unpack(data, &header); + rtp_header_unpack(payload, &header); if (header.pt != packet_type % 128) { - LOGGER_WARNING(m->log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d", + LOGGER_WARNING(log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d", header.pt, packet_type % 128); - return -1; + return; } if (header.pt != session->payload_type % 128) { - LOGGER_WARNING(m->log, "RTPHeader packet type does not match this session's payload type: %d != %d", + LOGGER_WARNING(log, "RTPHeader packet type does not match this session's payload type: %d != %d", header.pt, session->payload_type % 128); - return -1; + return; } if ((header.flags & RTP_LARGE_FRAME) != 0 && header.offset_full >= header.data_length_full) { - LOGGER_ERROR(m->log, "Invalid video packet: frame offset (%u) >= full frame length (%u)", + LOGGER_ERROR(log, "Invalid video packet: frame offset (%u) >= full frame length (%u)", (unsigned)header.offset_full, (unsigned)header.data_length_full); - return -1; + return; } if (header.offset_lower >= header.data_length_lower) { - LOGGER_ERROR(m->log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)", + LOGGER_ERROR(log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)", (unsigned)header.offset_lower, (unsigned)header.data_length_lower); - return -1; + return; } - LOGGER_DEBUG(m->log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128); + LOGGER_DEBUG(log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128); // The sender uses the new large-frame capable protocol and is sending a // video packet. if ((header.flags & RTP_LARGE_FRAME) != 0 && header.pt == (RTP_TYPE_VIDEO % 128)) { - return handle_video_packet(session, &header, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE, m->log); + handle_video_packet(log, session, &header, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE); + return; } // everything below here is for the old 16 bit protocol ------------------ - if (header.data_length_lower == length - RTP_HEADER_SIZE) { + if (header.data_length_lower == payload_size - RTP_HEADER_SIZE) { /* The message is sent in single part */ /* Message is not late; pick up the latest parameters */ session->rsequnum = header.sequnum; session->rtimestamp = header.timestamp; - bwc_add_recv(session->bwc, length); + bwc_add_recv(session->bwc, payload_size); /* Invoke processing of active multiparted message */ if (session->mp != nullptr) { - session->mcb(session->m->mono_time, session->cs, session->mp); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, session->mp); session->mp = nullptr; } /* The message came in the allowed time; */ - return session->mcb(session->m->mono_time, session->cs, new_message(&header, length - RTP_HEADER_SIZE, - data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE)); + session->mp = new_message(log, &header, payload_size - RTP_HEADER_SIZE, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, session->mp); + session->mp = nullptr; + return; } /* The message is sent in multiple parts */ @@ -527,24 +549,26 @@ static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t /* First case */ /* Make sure we have enough allocated memory */ - if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE || + if (session->mp->header.data_length_lower - session->mp->len < payload_size - RTP_HEADER_SIZE || session->mp->header.data_length_lower <= header.offset_lower) { /* There happened to be some corruption on the stream; * continue wihtout this part */ - return 0; + return; } - memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE, - length - RTP_HEADER_SIZE); - session->mp->len += length - RTP_HEADER_SIZE; - bwc_add_recv(session->bwc, length); + memcpy(session->mp->data + header.offset_lower, &payload[RTP_HEADER_SIZE], + payload_size - RTP_HEADER_SIZE); + session->mp->len += payload_size - RTP_HEADER_SIZE; + bwc_add_recv(session->bwc, payload_size); if (session->mp->len == session->mp->header.data_length_lower) { /* Received a full message; now push it for the further * processing. */ - session->mcb(session->m->mono_time, session->cs, session->mp); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, session->mp); session->mp = nullptr; } } else { @@ -553,17 +577,19 @@ static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t /* The received message part is from the old message; * discard it. */ - return 0; + return; } /* Push the previous message for processing */ - session->mcb(session->m->mono_time, session->cs, session->mp); + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + assert(mt != nullptr); + session->mcb(mt, session->cs, session->mp); session->mp = nullptr; goto NEW_MULTIPARTED; } } else { - /* In this case threat the message as if it was received in order + /* In this case treat the message as if it was received in order */ /* This is also a point for new multiparted messages */ NEW_MULTIPARTED: @@ -571,21 +597,21 @@ static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t /* Message is not late; pick up the latest parameters */ session->rsequnum = header.sequnum; session->rtimestamp = header.timestamp; - bwc_add_recv(session->bwc, length); + bwc_add_recv(session->bwc, payload_size); /* Store message. */ - session->mp = new_message(&header, header.data_length_lower, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE); + session->mp = new_message(log, &header, header.data_length_lower, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE); if (session->mp != nullptr) { memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len); } else { - LOGGER_WARNING(m->log, "new_message() returned a null pointer"); - return -1; + LOGGER_WARNING(log, "new_message() returned a null pointer"); + return; } } - return 0; + return; } size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header) @@ -647,24 +673,29 @@ size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header) return p - data; } -RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber, +static uint32_t rtp_random_u32(void) +{ + // HINT: uses libsodium function + return randombytes_random(); +} + +RTPSession *rtp_new(const Logger *log, int payload_type, Tox *tox, ToxAV *toxav, uint32_t friendnumber, BWController *bwc, void *cs, rtp_m_cb *mcb) { assert(mcb != nullptr); assert(cs != nullptr); - assert(m != nullptr); RTPSession *session = (RTPSession *)calloc(1, sizeof(RTPSession)); if (session == nullptr) { - LOGGER_WARNING(m->log, "Alloc failed! Program might misbehave!"); + LOGGER_WARNING(log, "Alloc failed! Program might misbehave!"); return nullptr; } session->work_buffer_list = (struct RTPWorkBufferList *)calloc(1, sizeof(struct RTPWorkBufferList)); if (session->work_buffer_list == nullptr) { - LOGGER_ERROR(m->log, "out of memory while allocating work buffer list"); + LOGGER_ERROR(log, "out of memory while allocating work buffer list"); free(session); return nullptr; } @@ -672,11 +703,12 @@ RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnum // First entry is free. session->work_buffer_list->next_free_entry = 0; - session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : random_u32(m->rng); + session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : rtp_random_u32(); // Zoff: what is this?? session->payload_type = payload_type; - session->m = m; session->tox = tox; + session->toxav = toxav; session->friend_number = friendnumber; + session->rtp_receive_active = true; // set NULL just in case session->mp = nullptr; @@ -687,26 +719,18 @@ RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnum session->cs = cs; session->mcb = mcb; - if (-1 == rtp_allow_receiving(session)) { - LOGGER_WARNING(m->log, "Failed to start rtp receiving mode"); - free(session->work_buffer_list); - free(session); - return nullptr; - } - return session; } -void rtp_kill(RTPSession *session) +void rtp_kill(const Logger *log, RTPSession *session) { if (session == nullptr) { + LOGGER_WARNING(log, "No session"); return; } - LOGGER_DEBUG(session->m->log, "Terminated RTP session: %p", (void *)session); - rtp_stop_receiving(session); - - LOGGER_DEBUG(session->m->log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d", + LOGGER_DEBUG(log, "Terminated RTP session: %p", (void *)session); + LOGGER_DEBUG(log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d", (int)session->work_buffer_list->next_free_entry); for (int8_t i = 0; i < session->work_buffer_list->next_free_entry; ++i) { @@ -716,114 +740,123 @@ void rtp_kill(RTPSession *session) free(session); } -int rtp_allow_receiving(RTPSession *session) +void rtp_allow_receiving_mark(RTPSession *session) { - if (session == nullptr) { - return -1; + if (session != nullptr) { + session->rtp_receive_active = true; } +} - if (m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, - handle_rtp_packet, session) == -1) { - LOGGER_WARNING(session->m->log, "Failed to register rtp receive handler"); - return -1; +void rtp_stop_receiving_mark(RTPSession *session) +{ + if (session != nullptr) { + session->rtp_receive_active = false; } +} - LOGGER_DEBUG(session->m->log, "Started receiving on session: %p", (void *)session); - return 0; +void rtp_allow_receiving(Tox *tox) +{ + // register callback + tox_callback_friend_lossy_packet_per_pktid(tox, handle_rtp_packet, RTP_TYPE_AUDIO); + tox_callback_friend_lossy_packet_per_pktid(tox, handle_rtp_packet, RTP_TYPE_VIDEO); } -int rtp_stop_receiving(RTPSession *session) +void rtp_stop_receiving(Tox *tox) { - if (session == nullptr) { - return -1; - } + // UN-register callback + tox_callback_friend_lossy_packet_per_pktid(tox, nullptr, RTP_TYPE_AUDIO); + tox_callback_friend_lossy_packet_per_pktid(tox, nullptr, RTP_TYPE_VIDEO); +} + +static void rtp_send_piece(const Logger *log, Tox *tox, uint32_t friend_number, const struct RTPHeader *header, + const uint8_t *data, uint8_t *rdata, uint16_t length) +{ + rtp_header_pack(rdata + 1, header); + memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); - m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, nullptr, nullptr); + Tox_Err_Friend_Custom_Packet error; + tox_friend_send_lossy_packet(tox, friend_number, + rdata, length + RTP_HEADER_SIZE + 1, &error); - LOGGER_DEBUG(session->m->log, "Stopped receiving on session: %p", (void *)session); - return 0; + if (error != TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { + char *netstrerror = net_new_strerror(net_error()); + LOGGER_WARNING(log, "RTP send failed (len: %d)! tox error: %s, net error: %s", + length + RTP_HEADER_SIZE + 1, tox_err_friend_custom_packet_to_string(error), netstrerror); + net_kill_strerror(netstrerror); + } } -/** - * Send a frame of audio or video data, chunked in @ref RTPMessage instances. - * - * @param session The A/V session to send the data for. - * @param data A byte array of length @p length. - * @param length The number of bytes to send from @p data. - * @param is_keyframe Whether this video frame is a key frame. If it is an - * audio frame, this parameter is ignored. - */ -int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, - bool is_keyframe, const Logger *log) +static struct RTPHeader rtp_default_header(const RTPSession *session, uint32_t length, bool is_keyframe) { - if (session == nullptr) { - LOGGER_ERROR(log, "No session!"); - return -1; + uint16_t length_safe = (uint16_t)length; + + if (length > UINT16_MAX) { + length_safe = UINT16_MAX; } struct RTPHeader header = {0}; - header.ve = 2; // this is unused in toxav + if (is_keyframe) { + header.flags |= RTP_KEY_FRAME; + } - header.pe = 0; + if (session->payload_type == RTP_TYPE_VIDEO) { + header.flags |= RTP_LARGE_FRAME; + } + header.ve = 2; // this is unused in toxav + header.pe = 0; header.xe = 0; - header.cc = 0; - header.ma = 0; - header.pt = session->payload_type % 128; - header.sequnum = session->sequnum; - - header.timestamp = current_time_monotonic(session->m->mono_time); - + Mono_Time *mt = toxav_get_av_mono_time(session->toxav); + if (mt != nullptr) { + header.timestamp = current_time_monotonic(mt); + } else { + header.timestamp = 0; + } header.ssrc = session->ssrc; - header.offset_lower = 0; - - // here the highest bits gets stripped anyway, no need to do keyframe bit magic here! - header.data_length_lower = length; - - if (session->payload_type == RTP_TYPE_VIDEO) { - header.flags = RTP_LARGE_FRAME; - } - - uint16_t length_safe = (uint16_t)length; - - if (length > UINT16_MAX) { - length_safe = UINT16_MAX; - } - header.data_length_lower = length_safe; header.data_length_full = length; // without header header.offset_lower = 0; header.offset_full = 0; - if (is_keyframe) { - header.flags |= RTP_KEY_FRAME; + return header; +} + +/** + * @brief Send a frame of audio or video data, chunked in @ref RTPMessage instances. + * + * @param session The A/V session to send the data for. + * @param data A byte array of length @p length. + * @param length The number of bytes to send from @p data. + * @param is_keyframe Whether this video frame is a key frame. If it is an + * audio frame, this parameter is ignored. + */ +int rtp_send_data(const Logger *log, RTPSession *session, const uint8_t *data, uint32_t length, + bool is_keyframe) +{ + if (session == nullptr) { + return -1; } - const uint16_t rdata_size = length + RTP_HEADER_SIZE + 1; + const uint16_t rdata_size = min_u32(length + RTP_HEADER_SIZE + 1, MAX_CRYPTO_DATA_SIZE); VLA(uint8_t, rdata, rdata_size); memset(rdata, 0, rdata_size); rdata[0] = session->payload_type; // packet id == payload_type + struct RTPHeader header = rtp_default_header(session, length, is_keyframe); + if (MAX_CRYPTO_DATA_SIZE > (length + RTP_HEADER_SIZE + 1)) { /* * The length is lesser than the maximum allowed length (including header) * Send the packet in single piece. */ - rtp_header_pack(rdata + 1, &header); - memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); - - if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, rdata_size)) { - char *netstrerror = net_new_strerror(net_error()); - LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! net error: %s", - rdata_size, netstrerror); - net_kill_strerror(netstrerror); - } + assert(length < UINT16_MAX); + rtp_send_piece(log, session->tox, session->friend_number, &header, data, rdata, length); } else { /* * The length is greater than the maximum allowed length (including header) @@ -833,16 +866,7 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1); while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) { - rtp_header_pack(rdata + 1, &header); - memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); - - if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, - rdata, piece + RTP_HEADER_SIZE + 1)) { - char *netstrerror = net_new_strerror(net_error()); - LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s", - piece + RTP_HEADER_SIZE + 1, netstrerror); - net_kill_strerror(netstrerror); - } + rtp_send_piece(log, session->tox, session->friend_number, &header, data + sent, rdata, piece); sent += piece; header.offset_lower = sent; @@ -853,16 +877,7 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, piece = length - sent; if (piece != 0) { - rtp_header_pack(rdata + 1, &header); - memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); - - if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, - piece + RTP_HEADER_SIZE + 1)) { - char *netstrerror = net_new_strerror(net_error()); - LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s", - piece + RTP_HEADER_SIZE + 1, netstrerror); - net_kill_strerror(netstrerror); - } + rtp_send_piece(log, session->tox, session->friend_number, &header, data + sent, rdata, piece); } } diff --git a/toxav/rtp.h b/toxav/rtp.h index 8acd48d061..1e2e2e8f0d 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -9,7 +9,6 @@ #include "bwcontroller.h" -#include "../toxcore/Messenger.h" #include "../toxcore/logger.h" #include "../toxcore/tox.h" @@ -36,6 +35,11 @@ typedef enum RTP_Type { RTP_TYPE_VIDEO = 193, } RTP_Type; +#ifndef TOXAV_DEFINED +#define TOXAV_DEFINED +typedef struct ToxAV ToxAV; +#endif /* TOXAV_DEFINED */ + /** * A bit mask (up to 64 bits) specifying features of the current frame affecting * the behaviour of the decoder. @@ -157,14 +161,19 @@ typedef struct RTPSession { struct RTPMessage *mp; /* Expected parted message */ struct RTPWorkBufferList *work_buffer_list; uint8_t first_packets_counter; /* dismiss first few lost video packets */ - Messenger *m; + const Logger *log; Tox *tox; + ToxAV *toxav; uint32_t friend_number; + bool rtp_receive_active; /* if this is set to false then incoming rtp packets will not be processed by handle_rtp_packet() */ BWController *bwc; void *cs; rtp_m_cb *mcb; } RTPSession; + +void handle_rtp_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, void *user_data); + /** * Serialise an RTPHeader to bytes to be sent over the network. * @@ -183,13 +192,16 @@ size_t rtp_header_pack(uint8_t *rdata, const struct RTPHeader *header); */ size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header); -RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber, +RTPSession *rtp_new(const Logger *log, int payload_type, Tox *tox, ToxAV *toxav, uint32_t friendnumber, BWController *bwc, void *cs, rtp_m_cb *mcb); -void rtp_kill(RTPSession *session); -int rtp_allow_receiving(RTPSession *session); -int rtp_stop_receiving(RTPSession *session); +void rtp_kill(const Logger *log, RTPSession *session); +void rtp_allow_receiving_mark(RTPSession *session); +void rtp_stop_receiving_mark(RTPSession *session); +void rtp_allow_receiving(Tox *tox); +void rtp_stop_receiving(Tox *tox); + /** - * Send a frame of audio or video data, chunked in @ref RTPMessage instances. + * @brief Send a frame of audio or video data, chunked in @ref RTPMessage instances. * * @param session The A/V session to send the data for. * @param data A byte array of length @p length. @@ -197,8 +209,8 @@ int rtp_stop_receiving(RTPSession *session); * @param is_keyframe Whether this video frame is a key frame. If it is an * audio frame, this parameter is ignored. */ -int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, - bool is_keyframe, const Logger *log); +int rtp_send_data(const Logger *log, RTPSession *session, const uint8_t *data, uint32_t length, + bool is_keyframe); #ifdef __cplusplus } /* extern "C" */ diff --git a/toxav/toxav.c b/toxav/toxav.c index 6bae7a91d1..dcb4597d66 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -12,11 +12,15 @@ #include "msi.h" #include "rtp.h" +#include "toxav_hacks.h" -#include "../toxcore/Messenger.h" #include "../toxcore/ccompat.h" #include "../toxcore/logger.h" #include "../toxcore/mono_time.h" +#include "../toxcore/net_crypto.h" +#include "../toxcore/network.h" +#include "../toxcore/tox.h" +#include "../toxcore/tox_private.h" #include "../toxcore/tox_struct.h" #include "../toxcore/util.h" @@ -36,7 +40,12 @@ // iteration interval that is used when no call is active #define IDLE_ITERATION_INTERVAL_MS 200 -typedef struct ToxAVCall { +#ifndef TOXAV_CALL_DEFINED +#define TOXAV_CALL_DEFINED +typedef struct ToxAVCall ToxAVCall; +#endif /* TOXAV_CALL_DEFINED */ + +struct ToxAVCall { ToxAV *av; pthread_mutex_t mutex_audio[1]; @@ -63,7 +72,7 @@ typedef struct ToxAVCall { struct ToxAVCall *prev; struct ToxAVCall *next; -} ToxAVCall; +}; /** Decode time statistics */ typedef struct DecodeTimeStats { @@ -79,8 +88,8 @@ typedef struct DecodeTimeStats { } DecodeTimeStats; struct ToxAV { + Logger *log; Tox *tox; - Messenger *m; MSISession *msi; /* Two-way storage: first is array of calls and second is list of calls with head and tail */ @@ -111,8 +120,8 @@ struct ToxAV { /* keep track of decode times for audio and video */ DecodeTimeStats audio_stats; DecodeTimeStats video_stats; - /** ToxAV's own mono_time instance */ - Mono_Time *toxav_mono_time; + + Mono_Time *toxav_mono_time; // ToxAV's own mono_time instance }; static void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, void *user_data); @@ -127,11 +136,55 @@ static bool audio_bit_rate_invalid(uint32_t bit_rate); static bool video_bit_rate_invalid(uint32_t bit_rate); static bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state); static ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, Toxav_Err_Call *error); -static ToxAVCall *call_get(ToxAV *av, uint32_t friend_number); static ToxAVCall *call_remove(ToxAVCall *call); static bool call_prepare_transmission(ToxAVCall *call); static void call_kill_transmission(ToxAVCall *call); +MSISession *tox_av_msi_get(const ToxAV *av) +{ + if (av == nullptr) { + return nullptr; + } + + return av->msi; +} + +ToxAVCall *call_get(ToxAV *av, uint32_t friend_number) +{ + if (av == nullptr) { + return nullptr; + } + + /* Assumes mutex locked */ + if (av->calls == nullptr || av->calls_tail < friend_number) { + return nullptr; + } + + return av->calls[friend_number]; +} + +RTPSession *rtp_session_get(ToxAVCall *call, int payload_type) +{ + if (call == nullptr) { + return nullptr; + } + + if (payload_type == RTP_TYPE_VIDEO) { + return call->video_rtp; + } else { + return call->audio_rtp; + } +} + +BWController *bwc_controller_get(const ToxAVCall *call) +{ + if (call == nullptr) { + return nullptr; + } + + return call->bwc; +} + /** * @brief initialize d with default values * @param d struct to be initialized, must not be nullptr @@ -155,33 +208,26 @@ ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error) goto RETURN; } - // TODO(iphydf): Don't rely on toxcore internals. - Messenger *m; - m = tox->m; - - if (m->msi_packet != nullptr) { - rc = TOXAV_ERR_NEW_MULTIPLE; - goto RETURN; - } - av = (ToxAV *)calloc(1, sizeof(ToxAV)); if (av == nullptr) { - LOGGER_WARNING(m->log, "Allocation failed!"); rc = TOXAV_ERR_NEW_MALLOC; goto RETURN; } if (create_recursive_mutex(av->mutex) != 0) { - LOGGER_WARNING(m->log, "Mutex creation failed!"); rc = TOXAV_ERR_NEW_MALLOC; goto RETURN; } + av->log = tox->m->log; av->tox = tox; - av->m = m; + av->msi = msi_new(av->log, av->tox); + + rtp_allow_receiving(av->tox); + bwc_allow_receiving(av->tox); + av->toxav_mono_time = mono_time_new(tox->sys.mem, nullptr, nullptr); - av->msi = msi_new(av->m); if (av->msi == nullptr) { pthread_mutex_destroy(av->mutex); @@ -193,6 +239,9 @@ ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error) init_decode_time_stats(&av->video_stats); av->msi->av = av; + // save ToxAV object into toxcore + tox_set_av_object(av->tox, av); + msi_callback_invite(av->msi, callback_invite); msi_callback_start(av->msi, callback_start); msi_callback_end(av->msi, callback_end); @@ -207,12 +256,15 @@ ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error) } if (rc != TOXAV_ERR_NEW_OK) { - free(av); - av = nullptr; + if (av != nullptr) { + free(av); + av = nullptr; + } } return av; } + void toxav_kill(ToxAV *av) { if (av == nullptr) { @@ -221,8 +273,16 @@ void toxav_kill(ToxAV *av) pthread_mutex_lock(av->mutex); + // unregister callbacks + for (uint8_t i = PACKET_ID_RANGE_LOSSY_AV_START; i <= PACKET_ID_RANGE_LOSSY_AV_END; ++i) { + tox_callback_friend_lossy_packet_per_pktid(av->tox, nullptr, i); + } + + rtp_stop_receiving(av->tox); + bwc_stop_receiving(av->tox); + /* To avoid possible deadlocks */ - while (av->msi != nullptr && msi_kill(av->msi, av->m->log) != 0) { + while (av->msi != nullptr && msi_kill(av->log, av->tox, av->msi) != 0) { pthread_mutex_unlock(av->mutex); pthread_mutex_lock(av->mutex); } @@ -243,13 +303,22 @@ void toxav_kill(ToxAV *av) pthread_mutex_unlock(av->mutex); pthread_mutex_destroy(av->mutex); + // set ToxAV object to NULL in toxcore, to signal ToxAV has been shutdown + tox_set_av_object(av->tox, nullptr); + free(av); } + Tox *toxav_get_tox(const ToxAV *av) { return av->tox; } +const Logger *toxav_get_logger(const ToxAV *av) +{ + return av->log; +} + uint32_t toxav_audio_iteration_interval(const ToxAV *av) { return av->calls != nullptr ? av->audio_stats.interval : IDLE_ITERATION_INTERVAL_MS; @@ -276,10 +345,11 @@ uint32_t toxav_iteration_interval(const ToxAV *av) static void calc_interval(ToxAV *av, DecodeTimeStats *stats, int32_t frame_time, uint64_t start_time) { stats->interval = frame_time < stats->average ? 0 : (frame_time - stats->average); - stats->total += current_time_monotonic(av->m->mono_time) - start_time; + stats->total += current_time_monotonic(av->toxav_mono_time) - start_time; if (++stats->count == 3) { - stats->average = stats->total / 3 + 5; /* NOTE: Magic Offset for precision */ + /* NOTE: Magic Offset for precision */ + stats->average = stats->total / 3 + 5; stats->count = 0; stats->total = 0; } @@ -300,7 +370,6 @@ static void iterate_common(ToxAV *av, bool audio) } const uint64_t start = current_time_monotonic(av->toxav_mono_time); - // time until the first audio or video frame is over int32_t frame_time = IDLE_ITERATION_INTERVAL_MS; for (ToxAVCall *i = av->calls[av->calls_head]; i != nullptr; i = i->next) { @@ -311,6 +380,15 @@ static void iterate_common(ToxAV *av, bool audio) pthread_mutex_lock(i->toxav_call_mutex); pthread_mutex_unlock(av->mutex); + const uint32_t fid = i->friend_number; + const bool is_offline = check_peer_offline_status(av->log, av->tox, i->msi_call->session, fid); + + if (is_offline) { + pthread_mutex_unlock(i->toxav_call_mutex); + pthread_mutex_lock(av->mutex); + break; + } + if (audio) { ac_iterate(i->audio); @@ -329,8 +407,6 @@ static void iterate_common(ToxAV *av, bool audio) } } - const uint32_t fid = i->friend_number; - pthread_mutex_unlock(i->toxav_call_mutex); pthread_mutex_lock(av->mutex); @@ -342,8 +418,10 @@ static void iterate_common(ToxAV *av, bool audio) DecodeTimeStats *stats = audio ? &av->audio_stats : &av->video_stats; calc_interval(av, stats, frame_time, start); + pthread_mutex_unlock(av->mutex); } + void toxav_audio_iterate(ToxAV *av) { iterate_common(av, true); @@ -388,7 +466,7 @@ bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint call->previous_self_capabilities |= audio_bit_rate > 0 ? MSI_CAP_S_AUDIO : 0; call->previous_self_capabilities |= video_bit_rate > 0 ? MSI_CAP_S_VIDEO : 0; - if (msi_invite(av->msi, &call->msi_call, friend_number, call->previous_self_capabilities) != 0) { + if (msi_invite(av->log, av->msi, &call->msi_call, friend_number, call->previous_self_capabilities) != 0) { call_remove(call); rc = TOXAV_ERR_CALL_SYNC; goto RETURN; @@ -405,6 +483,7 @@ bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint return rc == TOXAV_ERR_CALL_OK; } + void toxav_callback_call(ToxAV *av, toxav_call_cb *callback, void *user_data) { pthread_mutex_lock(av->mutex); @@ -412,6 +491,7 @@ void toxav_callback_call(ToxAV *av, toxav_call_cb *callback, void *user_data) av->ccb_user_data = user_data; pthread_mutex_unlock(av->mutex); } + bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, Toxav_Err_Answer *error) { @@ -420,7 +500,7 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui Toxav_Err_Answer rc = TOXAV_ERR_ANSWER_OK; ToxAVCall *call; - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND; goto RETURN; } @@ -452,7 +532,7 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui call->previous_self_capabilities |= audio_bit_rate > 0 ? MSI_CAP_S_AUDIO : 0; call->previous_self_capabilities |= video_bit_rate > 0 ? MSI_CAP_S_VIDEO : 0; - if (msi_answer(call->msi_call, call->previous_self_capabilities) != 0) { + if (msi_answer(av->log, call->msi_call, call->previous_self_capabilities) != 0) { rc = TOXAV_ERR_ANSWER_SYNC; } @@ -465,6 +545,7 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui return rc == TOXAV_ERR_ANSWER_OK; } + void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *user_data) { pthread_mutex_lock(av->mutex); @@ -472,6 +553,7 @@ void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *u av->scb_user_data = user_data; pthread_mutex_unlock(av->mutex); } + static Toxav_Err_Call_Control call_control_handle_resume(const ToxAVCall *call) { /* Only act if paused and had media transfer active before */ @@ -479,12 +561,13 @@ static Toxav_Err_Call_Control call_control_handle_resume(const ToxAVCall *call) return TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; } - if (msi_change_capabilities(call->msi_call, call->previous_self_capabilities) == -1) { + if (msi_change_capabilities(call->av->log, call->msi_call, + call->previous_self_capabilities) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_allow_receiving(call->audio_rtp); - rtp_allow_receiving(call->video_rtp); + rtp_allow_receiving_mark(call->audio_rtp); + rtp_allow_receiving_mark(call->video_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } @@ -497,12 +580,12 @@ static Toxav_Err_Call_Control call_control_handle_pause(ToxAVCall *call) call->previous_self_capabilities = call->msi_call->self_capabilities; - if (msi_change_capabilities(call->msi_call, 0) == -1) { + if (msi_change_capabilities(call->av->log, call->msi_call, 0) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_stop_receiving(call->audio_rtp); - rtp_stop_receiving(call->video_rtp); + rtp_stop_receiving_mark(call->audio_rtp); + rtp_stop_receiving_mark(call->video_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } @@ -511,7 +594,7 @@ static Toxav_Err_Call_Control call_control_handle_cancel(ToxAVCall *call) /* Hang up */ pthread_mutex_lock(call->toxav_call_mutex); - if (msi_hangup(call->msi_call) != 0) { + if (msi_hangup(call->av->log, call->msi_call) != 0) { pthread_mutex_unlock(call->toxav_call_mutex); return TOXAV_ERR_CALL_CONTROL_SYNC; } @@ -531,13 +614,13 @@ static Toxav_Err_Call_Control call_control_handle_mute_audio(const ToxAVCall *ca return TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; } - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(call->av->log, call->msi_call, call-> msi_call->self_capabilities ^ MSI_CAP_R_AUDIO) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_stop_receiving(call->audio_rtp); + rtp_stop_receiving_mark(call->audio_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } static Toxav_Err_Call_Control call_control_handle_unmute_audio(const ToxAVCall *call) @@ -546,12 +629,12 @@ static Toxav_Err_Call_Control call_control_handle_unmute_audio(const ToxAVCall * return TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; } - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(call->av->log, call->msi_call, call-> msi_call->self_capabilities | MSI_CAP_R_AUDIO) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_allow_receiving(call->audio_rtp); + rtp_allow_receiving_mark(call->audio_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } static Toxav_Err_Call_Control call_control_handle_hide_video(const ToxAVCall *call) @@ -560,12 +643,12 @@ static Toxav_Err_Call_Control call_control_handle_hide_video(const ToxAVCall *ca return TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; } - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(call->av->log, call->msi_call, call-> msi_call->self_capabilities ^ MSI_CAP_R_VIDEO) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_stop_receiving(call->video_rtp); + rtp_stop_receiving_mark(call->video_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } static Toxav_Err_Call_Control call_control_handle_show_video(const ToxAVCall *call) @@ -574,12 +657,12 @@ static Toxav_Err_Call_Control call_control_handle_show_video(const ToxAVCall *ca return TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; } - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(call->av->log, call->msi_call, call-> msi_call->self_capabilities | MSI_CAP_R_VIDEO) == -1) { return TOXAV_ERR_CALL_CONTROL_SYNC; } - rtp_allow_receiving(call->video_rtp); + rtp_allow_receiving_mark(call->video_rtp); return TOXAV_ERR_CALL_CONTROL_OK; } static Toxav_Err_Call_Control call_control_handle(ToxAVCall *call, Toxav_Call_Control control) @@ -611,7 +694,7 @@ static Toxav_Err_Call_Control call_control_handle(ToxAVCall *call, Toxav_Call_Co } static Toxav_Err_Call_Control call_control(ToxAV *av, uint32_t friend_number, Toxav_Call_Control control) { - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { return TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND; } @@ -637,13 +720,14 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, Toxav_Call_Control co return rc == TOXAV_ERR_CALL_CONTROL_OK; } + bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_rate, Toxav_Err_Bit_Rate_Set *error) { Toxav_Err_Bit_Rate_Set rc = TOXAV_ERR_BIT_RATE_SET_OK; ToxAVCall *call; - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND; goto RETURN; } @@ -662,14 +746,14 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra goto RETURN; } - LOGGER_DEBUG(av->m->log, "Setting new audio bitrate to: %d", bit_rate); + LOGGER_DEBUG(av->log, "Setting new audio bitrate to: %d", bit_rate); if (call->audio_bit_rate == bit_rate) { - LOGGER_DEBUG(av->m->log, "Audio bitrate already set to: %d", bit_rate); + LOGGER_DEBUG(av->log, "Audio bitrate already set to: %d", bit_rate); } else if (bit_rate == 0) { - LOGGER_DEBUG(av->m->log, "Turned off audio sending"); + LOGGER_DEBUG(av->log, "Turned off audio sending"); - if (msi_change_capabilities(call->msi_call, call->msi_call-> + if (msi_change_capabilities(av->log, call->msi_call, call->msi_call-> self_capabilities ^ MSI_CAP_S_AUDIO) != 0) { pthread_mutex_unlock(av->mutex); rc = TOXAV_ERR_BIT_RATE_SET_SYNC; @@ -682,10 +766,10 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra pthread_mutex_lock(call->toxav_call_mutex); if (call->audio_bit_rate == 0) { - LOGGER_DEBUG(av->m->log, "Turned on audio sending"); + LOGGER_DEBUG(av->log, "Turned on audio sending"); /* The audio has been turned off before this */ - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(av->log, call->msi_call, call-> msi_call->self_capabilities | MSI_CAP_S_AUDIO) != 0) { pthread_mutex_unlock(call->toxav_call_mutex); pthread_mutex_unlock(av->mutex); @@ -693,7 +777,7 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra goto RETURN; } } else { - LOGGER_DEBUG(av->m->log, "Set new audio bit rate %d", bit_rate); + LOGGER_DEBUG(av->log, "Set new audio bit rate %d", bit_rate); } call->audio_bit_rate = bit_rate; @@ -709,13 +793,14 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra return rc == TOXAV_ERR_BIT_RATE_SET_OK; } + bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_rate, Toxav_Err_Bit_Rate_Set *error) { Toxav_Err_Bit_Rate_Set rc = TOXAV_ERR_BIT_RATE_SET_OK; ToxAVCall *call; - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND; goto RETURN; } @@ -734,15 +819,15 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra goto RETURN; } - LOGGER_DEBUG(av->m->log, "Setting new video bitrate to: %d", bit_rate); + LOGGER_DEBUG(av->log, "Setting new video bitrate to: %d", bit_rate); if (call->video_bit_rate == bit_rate) { - LOGGER_DEBUG(av->m->log, "Video bitrate already set to: %d", bit_rate); + LOGGER_DEBUG(av->log, "Video bitrate already set to: %d", bit_rate); } else if (bit_rate == 0) { - LOGGER_DEBUG(av->m->log, "Turned off video sending"); + LOGGER_DEBUG(av->log, "Turned off video sending"); /* Video sending is turned off; notify peer */ - if (msi_change_capabilities(call->msi_call, call->msi_call-> + if (msi_change_capabilities(av->log, call->msi_call, call->msi_call-> self_capabilities ^ MSI_CAP_S_VIDEO) != 0) { pthread_mutex_unlock(av->mutex); rc = TOXAV_ERR_BIT_RATE_SET_SYNC; @@ -754,10 +839,10 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra pthread_mutex_lock(call->toxav_call_mutex); if (call->video_bit_rate == 0) { - LOGGER_DEBUG(av->m->log, "Turned on video sending"); + LOGGER_DEBUG(av->log, "Turned on video sending"); /* The video has been turned off before this */ - if (msi_change_capabilities(call->msi_call, call-> + if (msi_change_capabilities(av->log, call->msi_call, call-> msi_call->self_capabilities | MSI_CAP_S_VIDEO) != 0) { pthread_mutex_unlock(call->toxav_call_mutex); pthread_mutex_unlock(av->mutex); @@ -765,7 +850,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra goto RETURN; } } else { - LOGGER_DEBUG(av->m->log, "Set new video bit rate %d", bit_rate); + LOGGER_DEBUG(av->log, "Set new video bit rate %d", bit_rate); } call->video_bit_rate = bit_rate; @@ -781,6 +866,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra return rc == TOXAV_ERR_BIT_RATE_SET_OK; } + void toxav_callback_audio_bit_rate(ToxAV *av, toxav_audio_bit_rate_cb *callback, void *user_data) { pthread_mutex_lock(av->mutex); @@ -788,6 +874,7 @@ void toxav_callback_audio_bit_rate(ToxAV *av, toxav_audio_bit_rate_cb *callback, av->abcb_user_data = user_data; pthread_mutex_unlock(av->mutex); } + void toxav_callback_video_bit_rate(ToxAV *av, toxav_video_bit_rate_cb *callback, void *user_data) { pthread_mutex_lock(av->mutex); @@ -795,13 +882,14 @@ void toxav_callback_video_bit_rate(ToxAV *av, toxav_video_bit_rate_cb *callback, av->vbcb_user_data = user_data; pthread_mutex_unlock(av->mutex); } + bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, Toxav_Err_Send_Frame *error) { Toxav_Err_Send_Frame rc = TOXAV_ERR_SEND_FRAME_OK; ToxAVCall *call; - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND; goto RETURN; } @@ -859,14 +947,14 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc dest + sizeof(sampling_rate), dest_size - sizeof(sampling_rate)); if (vrc < 0) { - LOGGER_WARNING(av->m->log, "Failed to encode frame %s", opus_strerror(vrc)); + LOGGER_WARNING(av->log, "Failed to encode frame %s", opus_strerror(vrc)); pthread_mutex_unlock(call->mutex_audio); rc = TOXAV_ERR_SEND_FRAME_INVALID; goto RETURN; } - if (rtp_send_data(call->audio_rtp, dest, vrc + sizeof(sampling_rate), false, av->m->log) != 0) { - LOGGER_WARNING(av->m->log, "Failed to send audio packet"); + if (rtp_send_data(av->log, call->audio_rtp, dest, vrc + sizeof(sampling_rate), false) != 0) { + LOGGER_WARNING(av->log, "Failed to send audio packet"); rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED; } } @@ -882,7 +970,7 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc return rc == TOXAV_ERR_SEND_FRAME_OK; } -static Toxav_Err_Send_Frame send_frames(const Logger *log, ToxAVCall *call) +static Toxav_Err_Send_Frame send_frames(const ToxAV *av, ToxAVCall *call) { vpx_codec_iter_t iter = nullptr; @@ -900,20 +988,15 @@ static Toxav_Err_Send_Frame send_frames(const Logger *log, ToxAVCall *call) const uint32_t frame_length_in_bytes = pkt->data.frame.sz; const int res = rtp_send_data( + av->log, call->video_rtp, (const uint8_t *)pkt->data.frame.buf, frame_length_in_bytes, - is_keyframe, - log); - - LOGGER_DEBUG(log, "+ _sending_FRAME_TYPE_==%s bytes=%d frame_len=%d", is_keyframe ? "K" : ".", - (int)pkt->data.frame.sz, (int)frame_length_in_bytes); - const uint8_t *const buf = (const uint8_t *)pkt->data.frame.buf; - LOGGER_DEBUG(log, "+ _sending_FRAME_ b0=%d b1=%d", buf[0], buf[1]); + is_keyframe); if (res < 0) { char *netstrerror = net_new_strerror(net_error()); - LOGGER_WARNING(log, "Could not send video frame: %s", netstrerror); + LOGGER_WARNING(av->log, "Could not send video frame: %s", netstrerror); net_kill_strerror(netstrerror); return TOXAV_ERR_SEND_FRAME_RTP_FAILED; } @@ -930,7 +1013,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u int vpx_encode_flags = 0; - if (!m_friend_exists(av->m, friend_number)) { + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND; goto RETURN; } @@ -965,7 +1048,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u goto RETURN; } - if (vc_reconfigure_encoder(call->video, call->video_bit_rate * 1000, width, height, -1) != 0) { + if (vc_reconfigure_encoder(call->video, call->video_bit_rate, width, height, -1) != 0) { pthread_mutex_unlock(call->mutex_video); rc = TOXAV_ERR_SEND_FRAME_INVALID; goto RETURN; @@ -974,13 +1057,13 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u if (call->video_rtp->ssrc < VIDEO_SEND_X_KEYFRAMES_FIRST) { // Key frame flag for first frames vpx_encode_flags = VPX_EFLAG_FORCE_KF; - LOGGER_DEBUG(av->m->log, "I_FRAME_FLAG:%d only-i-frame mode", call->video_rtp->ssrc); + LOGGER_DEBUG(av->log, "I_FRAME_FLAG:%d only-i-frame mode", call->video_rtp->ssrc); ++call->video_rtp->ssrc; } else if (call->video_rtp->ssrc == VIDEO_SEND_X_KEYFRAMES_FIRST) { // normal keyframe placement vpx_encode_flags = 0; - LOGGER_DEBUG(av->m->log, "I_FRAME_FLAG:%d normal mode", call->video_rtp->ssrc); + LOGGER_DEBUG(av->log, "I_FRAME_FLAG:%d normal mode", call->video_rtp->ssrc); ++call->video_rtp->ssrc; } @@ -1009,7 +1092,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u if (vrc != VPX_CODEC_OK) { pthread_mutex_unlock(call->mutex_video); - LOGGER_ERROR(av->m->log, "Could not encode video frame: %s", vpx_codec_err_to_string(vrc)); + LOGGER_ERROR(av->log, "Could not encode video frame: %s", vpx_codec_err_to_string(vrc)); rc = TOXAV_ERR_SEND_FRAME_INVALID; goto RETURN; } @@ -1017,7 +1100,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u ++call->video->frame_counter; - rc = send_frames(av->m->log, call); + rc = send_frames(av, call); pthread_mutex_unlock(call->mutex_video); @@ -1063,7 +1146,7 @@ static void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, ToxAVCall *call = (ToxAVCall *)user_data; assert(call != nullptr); - LOGGER_DEBUG(call->av->m->log, "Reported loss of %f%%", (double)loss * 100); + LOGGER_DEBUG(call->av->log, "Reported loss of %f%%", (double)loss * 100); /* if less than 10% data loss we do nothing! */ if (loss < 0.1F) { @@ -1075,7 +1158,7 @@ static void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, if (call->video_bit_rate != 0) { if (call->av->vbcb == nullptr) { pthread_mutex_unlock(call->av->mutex); - LOGGER_WARNING(call->av->m->log, "No callback to report loss on"); + LOGGER_WARNING(call->av->log, "No callback to report loss on"); return; } @@ -1085,7 +1168,7 @@ static void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, } else if (call->audio_bit_rate != 0) { if (call->av->abcb == nullptr) { pthread_mutex_unlock(call->av->mutex); - LOGGER_WARNING(call->av->m->log, "No callback to report loss on"); + LOGGER_WARNING(call->av->log, "No callback to report loss on"); return; } @@ -1096,6 +1179,7 @@ static void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, pthread_mutex_unlock(call->av->mutex); } + static int callback_invite(void *object, MSICall *call) { ToxAV *toxav = (ToxAV *)object; @@ -1104,7 +1188,7 @@ static int callback_invite(void *object, MSICall *call) ToxAVCall *av_call = call_new(toxav, call->friend_number, nullptr); if (av_call == nullptr) { - LOGGER_WARNING(toxav->m->log, "Failed to initialize call..."); + LOGGER_WARNING(toxav->log, "Failed to initialize call..."); pthread_mutex_unlock(toxav->mutex); return -1; } @@ -1124,6 +1208,7 @@ static int callback_invite(void *object, MSICall *call) pthread_mutex_unlock(toxav->mutex); return 0; } + static int callback_start(void *object, MSICall *call) { ToxAV *toxav = (ToxAV *)object; @@ -1152,6 +1237,7 @@ static int callback_start(void *object, MSICall *call) pthread_mutex_unlock(toxav->mutex); return 0; } + static int callback_end(void *object, MSICall *call) { ToxAV *toxav = (ToxAV *)object; @@ -1167,6 +1253,7 @@ static int callback_end(void *object, MSICall *call) pthread_mutex_unlock(toxav->mutex); return 0; } + static int callback_error(void *object, MSICall *call) { ToxAV *toxav = (ToxAV *)object; @@ -1182,21 +1269,22 @@ static int callback_error(void *object, MSICall *call) pthread_mutex_unlock(toxav->mutex); return 0; } + static int callback_capabilites(void *object, MSICall *call) { ToxAV *toxav = (ToxAV *)object; pthread_mutex_lock(toxav->mutex); if ((call->peer_capabilities & MSI_CAP_S_AUDIO) != 0) { - rtp_allow_receiving(call->av_call->audio_rtp); + rtp_allow_receiving_mark(call->av_call->audio_rtp); } else { - rtp_stop_receiving(call->av_call->audio_rtp); + rtp_stop_receiving_mark(call->av_call->audio_rtp); } if ((call->peer_capabilities & MSI_CAP_S_VIDEO) != 0) { - rtp_allow_receiving(call->av_call->video_rtp); + rtp_allow_receiving_mark(call->av_call->video_rtp); } else { - rtp_stop_receiving(call->av_call->video_rtp); + rtp_stop_receiving_mark(call->av_call->video_rtp); } invoke_call_state_callback(toxav, call->friend_number, call->peer_capabilities); @@ -1204,6 +1292,7 @@ static int callback_capabilites(void *object, MSICall *call) pthread_mutex_unlock(toxav->mutex); return 0; } + static bool audio_bit_rate_invalid(uint32_t bit_rate) { /* Opus RFC 6716 section-2.1.1 dictates the following: @@ -1211,6 +1300,7 @@ static bool audio_bit_rate_invalid(uint32_t bit_rate) */ return bit_rate < 6 || bit_rate > 510; } + static bool video_bit_rate_invalid(uint32_t bit_rate) { /* https://www.webmproject.org/docs/webm-sdk/structvpx__codec__enc__cfg.html shows the following: @@ -1222,6 +1312,7 @@ static bool video_bit_rate_invalid(uint32_t bit_rate) */ return bit_rate > UINT32_MAX; } + static bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state) { if (av->scb != nullptr) { @@ -1239,12 +1330,17 @@ static ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, Toxav_Err_Call *er Toxav_Err_Call rc = TOXAV_ERR_CALL_OK; ToxAVCall *call = nullptr; - if (!m_friend_exists(av->m, friend_number)) { + Tox_Err_Friend_Query f_con_query_error; + Tox_Connection f_con_status = TOX_CONNECTION_NONE; + + if (!tox_friend_exists(av->tox, friend_number)) { rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; goto RETURN; } - if (m_get_friend_connectionstatus(av->m, friend_number) < 1) { + f_con_status = tox_friend_get_connection_status(av->tox, friend_number, &f_con_query_error); + + if (f_con_status == TOX_CONNECTION_NONE) { rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; goto RETURN; } @@ -1323,16 +1419,6 @@ static ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, Toxav_Err_Call *er return call; } -static ToxAVCall *call_get(ToxAV *av, uint32_t friend_number) -{ - /* Assumes mutex locked */ - if (av->calls == nullptr || av->calls_tail < friend_number) { - return nullptr; - } - - return av->calls[friend_number]; -} - static ToxAVCall *call_remove(ToxAVCall *call) { if (call == nullptr) { @@ -1399,7 +1485,7 @@ static bool call_prepare_transmission(ToxAVCall *call) } if (call->active) { - LOGGER_WARNING(av->m->log, "Call already active!"); + LOGGER_WARNING(av->log, "Call already active!"); return true; } @@ -1412,43 +1498,37 @@ static bool call_prepare_transmission(ToxAVCall *call) } /* Prepare bwc */ - call->bwc = bwc_new(av->m, av->tox, call->friend_number, callback_bwc, call, av->toxav_mono_time); - - if (call->bwc == nullptr) { - LOGGER_ERROR(av->m->log, "Failed to create new bwc"); - goto FAILURE; - } + call->bwc = bwc_new(av->log, av->tox, call->friend_number, callback_bwc, call, av->toxav_mono_time); - { /* Prepare audio */ - call->audio = ac_new(av->toxav_mono_time, av->m->log, av, call->friend_number, av->acb, av->acb_user_data); + { /* Prepare audio */ + call->audio = ac_new(av->toxav_mono_time, av->log, av, call->friend_number, av->acb, av->acb_user_data); if (call->audio == nullptr) { - LOGGER_ERROR(av->m->log, "Failed to create audio codec session"); + LOGGER_ERROR(av->log, "Failed to create audio codec session"); goto FAILURE; } - call->audio_rtp = rtp_new(RTP_TYPE_AUDIO, av->m, av->tox, call->friend_number, call->bwc, + call->audio_rtp = rtp_new(av->log, RTP_TYPE_AUDIO, av->tox, av, call->friend_number, call->bwc, call->audio, ac_queue_message); if (call->audio_rtp == nullptr) { - LOGGER_ERROR(av->m->log, "Failed to create audio rtp session"); + LOGGER_ERROR(av->log, "Failed to create audio rtp session"); goto FAILURE; } } - - { /* Prepare video */ - call->video = vc_new(av->toxav_mono_time, av->m->log, av, call->friend_number, av->vcb, av->vcb_user_data); + { /* Prepare video */ + call->video = vc_new(av->log, av->toxav_mono_time, av, call->friend_number, av->vcb, av->vcb_user_data); if (call->video == nullptr) { - LOGGER_ERROR(av->m->log, "Failed to create video codec session"); + LOGGER_ERROR(av->log, "Failed to create video codec session"); goto FAILURE; } - call->video_rtp = rtp_new(RTP_TYPE_VIDEO, av->m, av->tox, call->friend_number, call->bwc, + call->video_rtp = rtp_new(av->log, RTP_TYPE_VIDEO, av->tox, av, call->friend_number, call->bwc, call->video, vc_queue_message); if (call->video_rtp == nullptr) { - LOGGER_ERROR(av->m->log, "Failed to create video rtp session"); + LOGGER_ERROR(av->log, "Failed to create video rtp session"); goto FAILURE; } } @@ -1458,11 +1538,11 @@ static bool call_prepare_transmission(ToxAVCall *call) FAILURE: bwc_kill(call->bwc); - rtp_kill(call->audio_rtp); + rtp_kill(av->log, call->audio_rtp); ac_kill(call->audio); call->audio_rtp = nullptr; call->audio = nullptr; - rtp_kill(call->video_rtp); + rtp_kill(av->log, call->video_rtp); vc_kill(call->video); call->video_rtp = nullptr; call->video = nullptr; @@ -1489,12 +1569,14 @@ static void call_kill_transmission(ToxAVCall *call) bwc_kill(call->bwc); - rtp_kill(call->audio_rtp); + const ToxAV *av = call->av; + + rtp_kill(av->log, call->audio_rtp); ac_kill(call->audio); call->audio_rtp = nullptr; call->audio = nullptr; - rtp_kill(call->video_rtp); + rtp_kill(av->log, call->video_rtp); vc_kill(call->video); call->video_rtp = nullptr; call->video = nullptr; @@ -1502,3 +1584,12 @@ static void call_kill_transmission(ToxAVCall *call) pthread_mutex_destroy(call->mutex_audio); pthread_mutex_destroy(call->mutex_video); } + +Mono_Time *toxav_get_av_mono_time(const ToxAV *av) +{ + if (av == nullptr) { + return nullptr; + } + + return av->toxav_mono_time; +} diff --git a/toxav/toxav.h b/toxav/toxav.h index 07d8d0eef7..a9e3485b67 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013-2015 Tox project. */ @@ -7,39 +7,40 @@ * @brief Public audio/video API for Tox clients. * * This API can handle multiple calls. Each call has its state, in very rare - * occasions the library can change the state of the call without apps knowledge. + * occasions the library can change the state of the call without apps + * knowledge. * * @section av_events Events and callbacks * - * As in Core API, events are handled by callbacks. One callback can be + * As in the toxcore API, events are handled by callbacks. One callback can be * registered per event. All events have a callback function type named - * `toxav_{event}_cb` and a function to register it named `toxav_callback_{event}`. - * Passing a NULL callback will result in no callback being registered for that - * event. Only one callback per event can be registered, so if a client needs - * multiple event listeners, it needs to implement the dispatch functionality - * itself. Unlike Core API, lack of some event handlers will cause the the - * library to drop calls before they are started. Hanging up call from a - * callback causes undefined behaviour. + * `toxav_{event}_cb` and a function to register it named + * `toxav_callback_{event}`. Passing a NULL callback will result in no callback + * being registered for that event. Only one callback per event can be + * registered, so if a client needs multiple event listeners, it needs to + * implement the dispatch functionality itself. Unlike the toxcore API, lack of + * some event handlers will cause the the library to drop calls before they are + * started. Hanging up call from a callback causes undefined behaviour. * * @section av_threading Threading implications * * Only toxav_iterate is thread-safe, all other functions must run from the - * tox thread. + * Tox thread. * * Important exceptions are the `*_iterate` and `*_iterate_interval` * functions. You have to choose either the single thread or the multi thread * functions and read their documentation. * * A common way to run ToxAV (multiple or single instance) is to have a thread, - * separate from tox instance thread, running a simple toxav_iterate loop, + * separate from Tox instance thread, running a simple toxav_iterate loop, * sleeping for `toxav_iteration_interval * milliseconds` on each iteration. * - * An important thing to note is that events are triggered from both tox and - * toxav thread (see above). Audio and video receive frame events are triggered - * from toxav thread while all the other events are triggered from tox thread. + * An important thing to note is that events are triggered from both Tox and + * ToxAV thread (see above). Audio and video receive frame events are triggered + * from ToxAV thread while all the other events are triggered from Tox thread. * - * Tox thread has priority with mutex mechanisms. Any api function can - * fail if mutexes are held by tox thread in which case they will set SYNC + * Tox thread has priority with mutex mechanisms. Any API function can + * fail if mutexes are held by Tox thread in which case they will set SYNC * error code. * * @subsection av_multi_threading Separate audio and video threads @@ -72,16 +73,19 @@ typedef struct Tox Tox; #endif /* !TOX_DEFINED */ #endif /* !APIGEN_IGNORE */ +#ifndef TOXAV_DEFINED +#define TOXAV_DEFINED /** * @brief The ToxAV instance type. * * Each ToxAV instance can be bound to only one Tox instance, and Tox instance * can have only one ToxAV instance. One must make sure to close ToxAV instance - * prior closing Tox instance otherwise undefined behaviour occurs. Upon - * closing of ToxAV instance, all active calls will be forcibly terminated - * without notifying peers. + * prior closing Tox instance otherwise undefined behaviour occurs. Upon closing + * of ToxAV instance, all active calls will be forcibly terminated without + * notifying peers. */ typedef struct ToxAV ToxAV; +#endif /* TOXAV_DEFINED */ /** @{ * @brief Creation and destruction @@ -100,8 +104,8 @@ typedef enum Toxav_Err_New { TOXAV_ERR_NEW_NULL, /** - * Memory allocation failure while trying to allocate structures required for - * the A/V session. + * Memory allocation failure while trying to allocate structures required + * for the A/V session. */ TOXAV_ERR_NEW_MALLOC, @@ -203,8 +207,8 @@ typedef enum Toxav_Err_Call { TOXAV_ERR_CALL_OK, /** - * A resource allocation error occurred while trying to create the structures - * required for the call. + * A resource allocation error occurred while trying to create the + * structures required for the call. */ TOXAV_ERR_CALL_MALLOC, @@ -245,10 +249,10 @@ typedef enum Toxav_Err_Call { * receiving are both enabled by default. * * @param friend_number The friend number of the friend that should be called. - * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable - * audio sending. - * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable - * video sending. + * @param audio_bit_rate Audio bit rate in kbit/sec. Set this to 0 to disable + * audio sending. + * @param video_bit_rate Video bit rate in kbit/sec. Set this to 0 to disable + * video sending. */ bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, Toxav_Err_Call *error); @@ -293,8 +297,9 @@ typedef enum Toxav_Err_Answer { TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND, /** - * The friend was valid, but they are not currently trying to initiate a call. - * This is also returned if this client is already in a call with the friend. + * The friend was valid, but they are not currently trying to initiate a + * call. This is also returned if this client is already in a call with the + * friend. */ TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING, @@ -313,10 +318,10 @@ typedef enum Toxav_Err_Answer { * enabled by default. * * @param friend_number The friend number of the friend that is calling. - * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable - * audio sending. - * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable - * video sending. + * @param audio_bit_rate Audio bit rate in kbit/sec. Set this to 0 to disable + * audio sending. + * @param video_bit_rate Video bit rate in kbit/sec. Set this to 0 to disable + * video sending. */ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, Toxav_Err_Answer *error); @@ -337,8 +342,8 @@ enum Toxav_Friend_Call_State { /** * Set by the AV core if an error occurred on the remote end or if friend * timed out. This is the final state after which no more state - * transitions can occur for the call. This call state will never be triggered - * in combination with other call states. + * transitions can occur for the call. This call state will never be + * triggered in combination with other call states. */ TOXAV_FRIEND_CALL_STATE_ERROR = 1, @@ -376,9 +381,9 @@ enum Toxav_Friend_Call_State { * * @param friend_number The friend number for which the call state changed. * @param state The bitmask of the new call state which is guaranteed to be - * different than the previous state. The state is set to 0 when the call is - * paused. The bitmask represents all the activities currently performed by the - * friend. + * different than the previous state. The state is set to 0 when the call is + * paused. The bitmask represents all the activities currently performed by + * the friend. */ typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data); @@ -397,8 +402,9 @@ void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *u typedef enum Toxav_Call_Control { /** - * Resume a previously paused call. Only valid if the pause was caused by this - * client, if not, this control is ignored. Not valid before the call is accepted. + * Resume a previously paused call. Only valid if the pause was caused by + * this client, if not, this control is ignored. Not valid before the call + * is accepted. */ TOXAV_CALL_CONTROL_RESUME, @@ -457,8 +463,8 @@ typedef enum Toxav_Err_Call_Control { TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND, /** - * This client is currently not in a call with the friend. Before the call is - * answered, only CANCEL is a valid control. + * This client is currently not in a call with the friend. Before the call + * is answered, only CANCEL is a valid control. */ TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL, @@ -474,7 +480,7 @@ typedef enum Toxav_Err_Call_Control { * Sends a call control command to a friend. * * @param friend_number The friend number of the friend this client is in a call - * with. + * with. * @param control The control command to send. * * @return true on success. @@ -530,8 +536,8 @@ typedef enum Toxav_Err_Send_Frame { TOXAV_ERR_SEND_FRAME_OK, /** - * In case of video, one of Y, U, or V was NULL. In case of audio, the samples - * data pointer was NULL. + * In case of video, one of Y, U, or V was NULL. In case of audio, the + * samples data pointer was NULL. */ TOXAV_ERR_SEND_FRAME_NULL, @@ -557,13 +563,13 @@ typedef enum Toxav_Err_Send_Frame { TOXAV_ERR_SEND_FRAME_INVALID, /** - * Either friend turned off audio or video receiving or we turned off sending - * for the said payload. + * Either friend turned off audio or video receiving or we turned off + * sending for the said payload. */ TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED, /** - * Failed to push frame through rtp interface. + * Failed to push frame through RTP interface. */ TOXAV_ERR_SEND_FRAME_RTP_FAILED, @@ -572,7 +578,8 @@ typedef enum Toxav_Err_Send_Frame { /** * Send an audio frame to a friend. * - * The expected format of the PCM data is: `[s1c1][s1c2][...][s2c1][s2c2][...]...` + * The expected format of the PCM data is: + * `[s1c1][s1c2][...][s2c1][s2c2][...]...` * Meaning: sample 1 for channel 1, sample 1 for channel 2, ... * For mono audio, this has no meaning, every sample is subsequent. For stereo, * this means the expected format is LRLRLR... with samples for left and right @@ -584,20 +591,20 @@ typedef enum Toxav_Err_Send_Frame { * `sample_count * channels`. * @param sample_count Number of samples in this frame. Valid numbers here are * `((sample rate) * (audio length) / 1000)`, where audio length can be - * 2.5, 5, 10, 20, 40 or 60 millseconds. + * 2.5, 5, 10, 20, 40 or 60 milliseconds. * @param channels Number of audio channels. Supported values are 1 and 2. * @param sampling_rate Audio sampling rate used in this frame. Valid sampling - * rates are 8000, 12000, 16000, 24000, or 48000. + * rates are 8000, 12000, 16000, 24000, or 48000. */ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t pcm[], size_t sample_count, uint8_t channels, uint32_t sampling_rate, Toxav_Err_Send_Frame *error); /** - * Set the bit rate to be used in subsequent video frames. + * Set the bit rate to be used in subsequent audio frames. * * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable. + * bit rate. + * @param bit_rate The new audio bit rate in kbit/sec. Set to 0 to disable. * * @return true on success. */ @@ -605,12 +612,12 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra /** * The function type for the audio_bit_rate callback. The event is triggered - * when the network becomes too saturated for current bit rates at which - * point core suggests new bit rates. + * when the network becomes too saturated for current bit rates at which point + * ToxAV suggests new bit rates. * * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param audio_bit_rate Suggested maximum audio bit rate in Kb/sec. + * bit rate. + * @param audio_bit_rate Suggested maximum audio bit rate in kbit/sec. */ typedef void toxav_audio_bit_rate_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void *user_data); @@ -623,12 +630,13 @@ void toxav_callback_audio_bit_rate(ToxAV *av, toxav_audio_bit_rate_cb *callback, /** * Send a video frame to a friend. * - * Y - plane should be of size: `height * width` - * U - plane should be of size: `(height/2) * (width/2)` - * V - plane should be of size: `(height/2) * (width/2)` + * The video frame needs to be planar YUV420. + * Y - plane should be of size: `width * height` + * U - plane should be of size: `(width/2) * (height/2)` + * V - plane should be of size: `(width/2) * (height/2)` * * @param friend_number The friend number of the friend to which to send a video - * frame. + * frame. * @param width Width of the frame in pixels. * @param height Height of the frame in pixels. * @param y Y (Luminance) plane data. @@ -637,17 +645,17 @@ void toxav_callback_audio_bit_rate(ToxAV *av, toxav_audio_bit_rate_cb *callback, */ bool toxav_video_send_frame( ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, - const uint8_t y[/*! height * width */], - const uint8_t u[/*! height/2 * width/2 */], - const uint8_t v[/*! height/2 * width/2 */], + const uint8_t y[/*! width * height */], + const uint8_t u[/*! width/2 * height/2 */], + const uint8_t v[/*! width/2 * height/2 */], Toxav_Err_Send_Frame *error); /** * Set the bit rate to be used in subsequent video frames. * * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param bit_rate The new video bit rate in Kb/sec. Set to 0 to disable. + * bit rate. + * @param bit_rate The new video bit rate in kbit/sec. Set to 0 to disable. * * @return true on success. */ @@ -655,12 +663,12 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_ra /** * The function type for the video_bit_rate callback. The event is triggered - * when the network becomes too saturated for current bit rates at which - * point core suggests new bit rates. + * when the network becomes too saturated for current bit rates at which point + * ToxAV suggests new bit rates. * * @param friend_number The friend number of the friend for which to set the - * bit rate. - * @param video_bit_rate Suggested maximum video bit rate in Kb/sec. + * bit rate. + * @param video_bit_rate Suggested maximum video bit rate in kbit/sec. */ typedef void toxav_video_bit_rate_cb(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data); @@ -714,7 +722,6 @@ void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb * @param y Luminosity plane. `Size = MAX(width, abs(ystride)) * height`. * @param u U chroma plane. `Size = MAX(width/2, abs(ustride)) * (height/2)`. * @param v V chroma plane. `Size = MAX(width/2, abs(vstride)) * (height/2)`. - * * @param ystride Luminosity plane stride. * @param ustride U chroma plane stride. * @param vstride V chroma plane stride. @@ -737,26 +744,28 @@ void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb #ifndef APIGEN_IGNORE /*** - * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove + * NOTE Compatibility with old ToxAV group calls. TODO(iphydf): remove * * TODO(iphydf): Use proper new API guidelines for these. E.g. don't use inline * function types, don't have per-callback userdata, especially don't have one * userdata per group. */ -// TODO(iphydf): Use this better typed one instead of the void-pointer one below. +// TODO(iphydf): Use this better typed one instead of the void-pointer one +// below. typedef void toxav_group_audio_cb(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t pcm[], uint32_t samples, uint8_t channels, uint32_t sample_rate, void *user_data); typedef void toxav_audio_data_cb(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t pcm[], uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata); -/** @brief Create a new toxav group. +/** @brief Create a new ToxAV group. * * @return group number on success. * @retval -1 on failure. * - * Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`. + * Note that total size of pcm in bytes is equal to + * `samples * channels * sizeof(int16_t)`. */ int32_t toxav_add_av_groupchat(Tox *tox, toxav_audio_data_cb *audio_callback, void *userdata); @@ -765,7 +774,8 @@ int32_t toxav_add_av_groupchat(Tox *tox, toxav_audio_data_cb *audio_callback, vo * @return group number on success. * @retval -1 on failure. * - * Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`. + * Note that total size of pcm in bytes is equal to + * `samples * channels * sizeof(int16_t)`. */ int32_t toxav_join_av_groupchat( Tox *tox, uint32_t friendnumber, const uint8_t data[], uint16_t length, @@ -776,7 +786,8 @@ int32_t toxav_join_av_groupchat( * @retval 0 on success. * @retval -1 on failure. * - * Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`. + * Note that total size of pcm in bytes is equal to + * `samples * channels * sizeof(int16_t)`. * * Valid number of samples are `(sample rate) * (audio length) / 1000` * (Valid values for audio length are: 2.5, 5, 10, 20, 40 or 60 ms) @@ -794,15 +805,16 @@ int32_t toxav_group_send_audio( * A/V must be enabled on a groupchat for audio to be sent to it and for * received audio to be handled. * - * An A/V group created with `toxav_add_av_groupchat` or `toxav_join_av_groupchat` - * will start with A/V enabled. + * An A/V group created with `toxav_add_av_groupchat` or + * `toxav_join_av_groupchat` will start with A/V enabled. * * An A/V group loaded from a savefile will start with A/V disabled. * * @retval 0 on success. * @retval -1 on failure. * - * Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`. + * Note that total size of pcm in bytes is equal to + * `samples * channels * sizeof(int16_t)`. */ int32_t toxav_groupchat_enable_av( Tox *tox, uint32_t groupnumber, diff --git a/toxav/toxav_hacks.h b/toxav/toxav_hacks.h new file mode 100644 index 0000000000..2b0382d080 --- /dev/null +++ b/toxav/toxav_hacks.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013-2015 Tox project. + */ +#ifndef C_TOXCORE_TOXAV_HACKS_H +#define C_TOXCORE_TOXAV_HACKS_H + +#include "bwcontroller.h" +#include "msi.h" +#include "rtp.h" + +#ifndef TOXAV_CALL_DEFINED +#define TOXAV_CALL_DEFINED +typedef struct ToxAVCall ToxAVCall; +#endif /* TOXAV_CALL_DEFINED */ + +non_null() +ToxAVCall *call_get(ToxAV *av, uint32_t friend_number); + +non_null() +RTPSession *rtp_session_get(ToxAVCall *call, int payload_type); + +non_null() +MSISession *tox_av_msi_get(const ToxAV *av); + +non_null() +BWController *bwc_controller_get(const ToxAVCall *call); + +non_null() +Mono_Time *toxav_get_av_mono_time(const ToxAV *av); + +non_null() +const Logger *toxav_get_logger(const ToxAV *av); + +#endif /* C_TOXCORE_TOXAV_HACKS_H */ diff --git a/toxav/video.c b/toxav/video.c index 301400b02f..4d1d5a9415 100644 --- a/toxav/video.c +++ b/toxav/video.c @@ -143,7 +143,7 @@ static void vc_init_encoder_cfg(const Logger *log, vpx_codec_enc_cfg_t *cfg, int #endif /* 0 */ } -VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number, +VCSession *vc_new(const Logger *log, Mono_Time *mono_time, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data) { VCSession *vc = (VCSession *)calloc(1, sizeof(VCSession)); @@ -216,7 +216,7 @@ VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t f /* Set encoder to some initial values */ - vpx_codec_enc_cfg_t cfg; + vpx_codec_enc_cfg_t cfg; vc_init_encoder_cfg(log, &cfg, 1); LOGGER_DEBUG(log, "Using VP8 codec for encoder (0.1)"); @@ -250,6 +250,7 @@ VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t f } #endif /* 0 */ + vc->linfts = current_time_monotonic(mono_time); vc->lcfd = 60; vc->vcb = cb; @@ -258,12 +259,14 @@ VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t f vc->av = av; vc->log = log; return vc; + BASE_CLEANUP_1: vpx_codec_destroy(vc->decoder); BASE_CLEANUP: pthread_mutex_destroy(vc->queue_mutex); rb_kill(vc->vbuf_raw); free(vc); + return nullptr; } diff --git a/toxav/video.h b/toxav/video.h index 57db74ac66..7bd54fa631 100644 --- a/toxav/video.h +++ b/toxav/video.h @@ -33,7 +33,6 @@ typedef struct VCSession { uint64_t linfts; /* Last received frame time stamp */ uint32_t lcfd; /* Last calculated frame duration for incoming video payload */ - const Logger *log; ToxAV *av; uint32_t friend_number; @@ -42,9 +41,10 @@ typedef struct VCSession { void *vcb_user_data; pthread_mutex_t queue_mutex[1]; + const Logger *log; } VCSession; -VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number, +VCSession *vc_new(const Logger *log, Mono_Time *mono_time, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data); void vc_kill(VCSession *vc); void vc_iterate(VCSession *vc); diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 0f313e2af5..5ea39880f2 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -1,12 +1,14 @@ -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test") exports_files( srcs = [ "tox.h", + "tox_dispatch.h", + "tox_events.h", "tox_private.h", ], - visibility = ["//c-toxcore:__pkg__"], + visibility = ["//c-toxcore:__subpackages__"], ) cc_library( @@ -100,14 +102,58 @@ cc_test( size = "small", srcs = ["util_test.cc"], deps = [ - ":crypto_core", - ":crypto_core_test_util", ":util", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], ) +cc_library( + name = "sort", + srcs = ["sort.c"], + hdrs = ["sort.h"], + deps = [ + ":attributes", + ":ccompat", + ":util", + ], +) + +cc_library( + name = "sort_test_util", + testonly = True, + srcs = ["sort_test_util.cc"], + hdrs = ["sort_test_util.hh"], + deps = [ + ":sort", + ":util", + ], +) + +cc_test( + name = "sort_test", + size = "small", + srcs = ["sort_test.cc"], + deps = [ + ":sort", + ":sort_test_util", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_binary( + name = "sort_bench", + testonly = True, + srcs = ["sort_bench.cc"], + deps = [ + ":mem", + ":sort", + ":sort_test_util", + "@benchmark", + ], +) + cc_library( name = "logger", srcs = ["logger.c"], @@ -121,6 +167,7 @@ cc_library( deps = [ ":attributes", ":ccompat", + ":mem", ], ) @@ -170,6 +217,7 @@ cc_library( deps = [ ":attributes", ":ccompat", + ":mem", ":util", "@libsodium", ], @@ -208,6 +256,7 @@ cc_test( deps = [ ":crypto_core", ":crypto_core_test_util", + ":mem_test_util", ":util", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", @@ -303,6 +352,7 @@ cc_library( name = "network", srcs = ["network.c"], hdrs = ["network.h"], + defines = ["HAVE_LIBEV"], visibility = [ "//c-toxcore/auto_tests:__pkg__", "//c-toxcore/other:__pkg__", @@ -319,6 +369,7 @@ cc_library( ":mem", ":mono_time", ":util", + "@ev", "@libsodium", "@psocket", "@pthread", @@ -332,6 +383,7 @@ cc_library( hdrs = ["network_test_util.hh"], deps = [ ":crypto_core", + ":mem", ":network", ":test_util", ], @@ -435,6 +487,7 @@ cc_library( ":network", ":ping_array", ":shared_key_cache", + ":sort", ":state", ":util", ], @@ -478,10 +531,12 @@ cc_test( cc_fuzz_test( name = "DHT_fuzz_test", size = "small", + testonly = True, srcs = ["DHT_fuzz_test.cc"], corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"], deps = [ ":DHT", + ":mem_test_util", "//c-toxcore/testing/fuzzing:fuzz_support", ], ) @@ -490,7 +545,11 @@ cc_library( name = "onion", srcs = ["onion.c"], hdrs = ["onion.h"], - visibility = ["//c-toxcore/auto_tests:__pkg__"], + visibility = [ + "//c-toxcore/auto_tests:__pkg__", + "//c-toxcore/other:__pkg__", + "//c-toxcore/other/bootstrap_daemon:__pkg__", + ], deps = [ ":DHT", ":attributes", @@ -509,7 +568,11 @@ cc_library( name = "forwarding", srcs = ["forwarding.c"], hdrs = ["forwarding.h"], - visibility = ["//c-toxcore/auto_tests:__pkg__"], + visibility = [ + "//c-toxcore/auto_tests:__pkg__", + "//c-toxcore/other:__pkg__", + "//c-toxcore/other/bootstrap_daemon:__pkg__", + ], deps = [ ":DHT", ":attributes", @@ -661,7 +724,10 @@ cc_library( name = "net_crypto", srcs = ["net_crypto.c"], hdrs = ["net_crypto.h"], - visibility = ["//c-toxcore/auto_tests:__pkg__"], + visibility = [ + "//c-toxcore/auto_tests:__pkg__", + "//c-toxcore/toxav:__pkg__", + ], deps = [ ":DHT", ":LAN_discovery", @@ -701,6 +767,7 @@ cc_library( ":network", ":onion", ":shared_key_cache", + ":sort", ":timed_auth", ":util", ], @@ -774,6 +841,7 @@ cc_library( ":crypto_core", ":group_announce", ":logger", + ":mem", ":mono_time", ":network", ":onion_announce", @@ -803,6 +871,7 @@ cc_library( ":onion", ":onion_announce", ":ping_array", + ":sort", ":timed_auth", ":util", ], @@ -968,9 +1037,11 @@ cc_library( ":crypto_core", ":friend_connection", ":logger", + ":mem", ":mono_time", ":net_crypto", ":network", + ":sort", ":state", ":util", ], diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 2567d1b5a8..da4ab11f09 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -9,7 +9,6 @@ #include "DHT.h" #include -#include #include #include "LAN_discovery.h" @@ -24,7 +23,9 @@ #include "ping.h" #include "ping_array.h" #include "shared_key_cache.h" +#include "sort.h" #include "state.h" +#include "util.h" /** The timeout after which a node is discarded completely. */ #define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL) @@ -279,7 +280,7 @@ const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key) #define CRYPTO_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE) -int create_request(const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key, +int create_request(const Memory *mem, const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, const uint8_t *recv_public_key, const uint8_t *data, uint32_t data_length, uint8_t request_id) { @@ -296,7 +297,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint uint8_t temp[MAX_CRYPTO_REQUEST_SIZE] = {0}; temp[0] = request_id; memcpy(temp + 1, data, data_length); - const int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, data_length + 1, + const int len = encrypt_data(mem, recv_public_key, send_secret_key, nonce, temp, data_length + 1, packet + CRYPTO_SIZE); if (len == -1) { @@ -312,7 +313,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint return len + CRYPTO_SIZE; } -int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, +int handle_request(const Memory *mem, const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, uint8_t *request_id, const uint8_t *packet, uint16_t packet_length) { if (self_public_key == nullptr || public_key == nullptr || data == nullptr || request_id == nullptr @@ -331,7 +332,7 @@ int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_ke memcpy(public_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE); const uint8_t *const nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2; uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; - int32_t len1 = decrypt_data(public_key, self_secret_key, nonce, + int32_t len1 = decrypt_data(mem, public_key, self_secret_key, nonce, packet + CRYPTO_SIZE, packet_length - CRYPTO_SIZE, temp); if (len1 == -1 || len1 == 0) { @@ -378,14 +379,14 @@ int dht_create_packet(const Memory *mem, const Random *rng, random_nonce(rng, nonce); - const int encrypted_length = encrypt_data_symmetric(shared_key, nonce, plain, plain_length, encrypted); + const int encrypted_length = encrypt_data_symmetric(mem, shared_key, nonce, plain, plain_length, encrypted); - if (encrypted_length == -1) { + if (encrypted_length < 0) { mem_delete(mem, encrypted); return -1; } - if (length < 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + encrypted_length) { + if (length < 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + (size_t)encrypted_length) { mem_delete(mem, encrypted); return -1; } @@ -755,49 +756,6 @@ int get_close_nodes( is_lan, want_announce); } -typedef struct DHT_Cmp_Data { - uint64_t cur_time; - const uint8_t *base_public_key; - Client_data entry; -} DHT_Cmp_Data; - -non_null() -static int dht_cmp_entry(const void *a, const void *b) -{ - const DHT_Cmp_Data *cmp1 = (const DHT_Cmp_Data *)a; - const DHT_Cmp_Data *cmp2 = (const DHT_Cmp_Data *)b; - const Client_data entry1 = cmp1->entry; - const Client_data entry2 = cmp2->entry; - const uint8_t *cmp_public_key = cmp1->base_public_key; - - const bool t1 = assoc_timeout(cmp1->cur_time, &entry1.assoc4) && assoc_timeout(cmp1->cur_time, &entry1.assoc6); - const bool t2 = assoc_timeout(cmp2->cur_time, &entry2.assoc4) && assoc_timeout(cmp2->cur_time, &entry2.assoc6); - - if (t1 && t2) { - return 0; - } - - if (t1) { - return -1; - } - - if (t2) { - return 1; - } - - const int closest = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); - - if (closest == 1) { - return 1; - } - - if (closest == 2) { - return -1; - } - - return 0; -} - #ifdef CHECK_ANNOUNCE_NODE non_null() static void set_announce_node_in_list(Client_data *list, uint32_t list_len, const uint8_t *public_key) @@ -870,7 +828,7 @@ static int handle_data_search_response(void *object, const IP_Port *source, const uint8_t *public_key = packet + 1; const uint8_t *shared_key = dht_get_shared_key_recv(dht, public_key); - if (decrypt_data_symmetric(shared_key, + if (decrypt_data_symmetric(dht->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, plain_len + CRYPTO_MAC_SIZE, @@ -914,31 +872,117 @@ static bool store_node_ok(const Client_data *client, uint64_t cur_time, const ui || id_closest(comp_public_key, client->public_key, public_key) == 2; } +typedef struct Client_data_Cmp { + const Memory *mem; + uint64_t cur_time; + const uint8_t *comp_public_key; +} Client_data_Cmp; + non_null() -static void sort_client_list(const Memory *mem, Client_data *list, uint64_t cur_time, unsigned int length, - const uint8_t *comp_public_key) +static int client_data_cmp(const Client_data_Cmp *cmp, const Client_data *entry1, const Client_data *entry2) { - // Pass comp_public_key to qsort with each Client_data entry, so the - // comparison function can use it as the base of comparison. - DHT_Cmp_Data *cmp_list = (DHT_Cmp_Data *)mem_valloc(mem, length, sizeof(DHT_Cmp_Data)); + const bool t1 = assoc_timeout(cmp->cur_time, &entry1->assoc4) && assoc_timeout(cmp->cur_time, &entry1->assoc6); + const bool t2 = assoc_timeout(cmp->cur_time, &entry2->assoc4) && assoc_timeout(cmp->cur_time, &entry2->assoc6); - if (cmp_list == nullptr) { - return; + if (t1 && t2) { + return 0; } - for (uint32_t i = 0; i < length; ++i) { - cmp_list[i].cur_time = cur_time; - cmp_list[i].base_public_key = comp_public_key; - cmp_list[i].entry = list[i]; + if (t1) { + return -1; } - qsort(cmp_list, length, sizeof(DHT_Cmp_Data), dht_cmp_entry); + if (t2) { + return 1; + } - for (uint32_t i = 0; i < length; ++i) { - list[i] = cmp_list[i].entry; + const int closest = id_closest(cmp->comp_public_key, entry1->public_key, entry2->public_key); + + if (closest == 1) { + return 1; + } + + if (closest == 2) { + return -1; + } + + return 0; +} + +non_null() +static bool client_data_less_handler(const void *object, const void *a, const void *b) +{ + const Client_data_Cmp *cmp = (const Client_data_Cmp *)object; + const Client_data *entry1 = (const Client_data *)a; + const Client_data *entry2 = (const Client_data *)b; + + return client_data_cmp(cmp, entry1, entry2) < 0; +} + +non_null() +static const void *client_data_get_handler(const void *arr, uint32_t index) +{ + const Client_data *entries = (const Client_data *)arr; + return &entries[index]; +} + +non_null() +static void client_data_set_handler(void *arr, uint32_t index, const void *val) +{ + Client_data *entries = (Client_data *)arr; + const Client_data *entry = (const Client_data *)val; + entries[index] = *entry; +} + +non_null() +static void *client_data_subarr_handler(void *arr, uint32_t index, uint32_t size) +{ + Client_data *entries = (Client_data *)arr; + return &entries[index]; +} + +non_null() +static void *client_data_alloc_handler(const void *object, uint32_t size) +{ + const Client_data_Cmp *cmp = (const Client_data_Cmp *)object; + Client_data *tmp = (Client_data *)mem_valloc(cmp->mem, size, sizeof(Client_data)); + + if (tmp == nullptr) { + return nullptr; } - mem_delete(mem, cmp_list); + return tmp; +} + +non_null() +static void client_data_delete_handler(const void *object, void *arr, uint32_t size) +{ + const Client_data_Cmp *cmp = (const Client_data_Cmp *)object; + mem_delete(cmp->mem, arr); +} + +static const Sort_Funcs client_data_cmp_funcs = { + client_data_less_handler, + client_data_get_handler, + client_data_set_handler, + client_data_subarr_handler, + client_data_alloc_handler, + client_data_delete_handler, +}; + +non_null() +static void sort_client_list(const Memory *mem, Client_data *list, uint64_t cur_time, unsigned int length, + const uint8_t *comp_public_key) +{ + // Pass comp_public_key to merge_sort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + const Client_data_Cmp cmp = { + mem, + cur_time, + comp_public_key, + }; + + merge_sort(list, length, &cmp, &client_data_cmp_funcs); } non_null() @@ -1347,15 +1391,15 @@ static int sendnodes_ipv6(const DHT *dht, const IP_Port *ip_port, const uint8_t plain[0] = num_nodes; memcpy(plain + 1 + nodes_length, sendback_data, length); - const uint32_t crypto_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE; - const uint32_t data_size = 1 + nodes_length + length + crypto_size; + const uint16_t crypto_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE; + const uint16_t data_size = 1 + nodes_length + length + crypto_size; VLA(uint8_t, data, data_size); const int len = dht_create_packet(dht->mem, dht->rng, dht->self_public_key, shared_encryption_key, NET_PACKET_SEND_NODES_IPV6, plain, 1 + nodes_length + length, data, data_size); - if (len != data_size) { + if (len < 0 || (uint32_t)len != data_size) { return -1; } @@ -1381,6 +1425,7 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p uint8_t plain[CRYPTO_NODE_SIZE]; const uint8_t *shared_key = dht_get_shared_key_recv(dht, packet + 1); const int len = decrypt_data_symmetric( + dht->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, @@ -1442,6 +1487,7 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin VLA(uint8_t, plain, plain_size); const uint8_t *shared_key = dht_get_shared_key_sent(dht, packet + 1); const int len = decrypt_data_symmetric( + dht->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, @@ -1840,7 +1886,7 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key) return dht_getnodes(dht, ip_port, public_key, dht->self_public_key); } -bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, +bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled, uint16_t port, const uint8_t *public_key) { IP_Port ip_port_v64; @@ -1855,7 +1901,7 @@ bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, ip_extra = &ip_port_v4.ip; } - if (addr_resolve_or_parse_ip(dht->ns, address, &ip_port_v64.ip, ip_extra)) { + if (addr_resolve_or_parse_ip(dht->ns, dht->mem, address, &ip_port_v64.ip, ip_extra, dns_enabled)) { ip_port_v64.port = port; dht_bootstrap(dht, &ip_port_v64, public_key); @@ -2123,7 +2169,7 @@ static int send_nat_ping(const DHT *dht, const uint8_t *public_key, uint64_t pin memcpy(data + 1, &ping_id, sizeof(uint64_t)); /* 254 is NAT ping request packet id */ const int len = create_request( - dht->rng, dht->self_public_key, dht->self_secret_key, packet_data, public_key, + dht->mem, dht->rng, dht->self_public_key, dht->self_secret_key, packet_data, public_key, data, sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING); if (len == -1) { @@ -2458,7 +2504,7 @@ static int cryptopacket_handle(void *object, const IP_Port *source, const uint8_ uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; uint8_t number; - const int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, + const int len = handle_request(dht->mem, dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length); if (len == -1 || len == 0) { diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 19a9e1d937..f42670b434 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h @@ -99,7 +99,7 @@ extern "C" { * @return the length of the created packet on success. */ non_null() -int create_request(const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key, +int create_request(const Memory *mem, const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, const uint8_t *recv_public_key, const uint8_t *data, uint32_t data_length, uint8_t request_id); @@ -127,7 +127,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint */ non_null() int handle_request( - const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + const Memory *mem, const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, uint8_t *request_id, const uint8_t *packet, uint16_t packet_length); typedef struct IPPTs { @@ -404,12 +404,13 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key); * @param address can be a hostname or an IP address (IPv4 or IPv6). * @param ipv6enabled if false, the resolving sticks STRICTLY to IPv4 addresses. * Otherwise, the resolving looks for IPv6 addresses first, then IPv4 addresses. + * @param dns_enabled if false, the resolving does not use DNS, only IP addresses are supported. * * @retval true if the address could be converted into an IP address * @retval false otherwise */ non_null() -bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, +bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled, uint16_t port, const uint8_t *public_key); /** @brief Start sending packets after DHT loaded_friends_list and loaded_clients_list are set. diff --git a/toxcore/DHT_fuzz_test.cc b/toxcore/DHT_fuzz_test.cc index 868aedecf2..cedec7826d 100644 --- a/toxcore/DHT_fuzz_test.cc +++ b/toxcore/DHT_fuzz_test.cc @@ -6,19 +6,22 @@ #include #include "../testing/fuzzing/fuzz_support.hh" +#include "mem_test_util.hh" namespace { void TestHandleRequest(Fuzz_Data &input) { + const Test_Memory mem; + CONSUME_OR_RETURN(const uint8_t *self_public_key, input, CRYPTO_PUBLIC_KEY_SIZE); CONSUME_OR_RETURN(const uint8_t *self_secret_key, input, CRYPTO_SECRET_KEY_SIZE); uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t request[MAX_CRYPTO_REQUEST_SIZE]; uint8_t request_id; - handle_request(self_public_key, self_secret_key, public_key, request, &request_id, input.data(), - input.size()); + handle_request(mem, self_public_key, self_secret_key, public_key, request, &request_id, + input.data(), input.size()); } void TestUnpackNodes(Fuzz_Data &input) @@ -31,7 +34,8 @@ void TestUnpackNodes(Fuzz_Data &input) const int packed_count = unpack_nodes( nodes, node_count, &processed_data_len, input.data(), input.size(), tcp_enabled); if (packed_count > 0) { - Logger *logger = logger_new(); + const Memory *mem = os_memory(); + Logger *logger = logger_new(mem); std::vector packed(packed_count * PACKED_NODE_SIZE_IP6); const int packed_size = pack_nodes(logger, packed.data(), packed.size(), nodes, packed_count); diff --git a/toxcore/DHT_test.cc b/toxcore/DHT_test.cc index 1028fc7f18..f817efe921 100644 --- a/toxcore/DHT_test.cc +++ b/toxcore/DHT_test.cc @@ -274,6 +274,7 @@ TEST(AddToList, KeepsKeysInOrder) TEST(Request, CreateAndParse) { + Test_Memory mem; Test_Random rng; // Peers. @@ -293,32 +294,32 @@ TEST(Request, CreateAndParse) std::vector outgoing(919); random_bytes(rng, outgoing.data(), outgoing.size()); - EXPECT_LT(create_request(rng, sender.pk.data(), sender.sk.data(), packet.data(), + EXPECT_LT(create_request(mem, rng, sender.pk.data(), sender.sk.data(), packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id), 0); // Pop one element so the payload is 918 bytes. Packing should now succeed. outgoing.pop_back(); - const int max_sent_length = create_request(rng, sender.pk.data(), sender.sk.data(), + const int max_sent_length = create_request(mem, rng, sender.pk.data(), sender.sk.data(), packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id); ASSERT_GT(max_sent_length, 0); // success. // Check that handle_request rejects packets larger than the maximum created packet size. - EXPECT_LT(handle_request(receiver.pk.data(), receiver.sk.data(), pk.data(), incoming.data(), - &recvd_pkt_id, packet.data(), max_sent_length + 1), + EXPECT_LT(handle_request(mem, receiver.pk.data(), receiver.sk.data(), pk.data(), + incoming.data(), &recvd_pkt_id, packet.data(), max_sent_length + 1), 0); // Now try all possible packet sizes from max (918) to 0. while (!outgoing.empty()) { // Pack: - const int sent_length = create_request(rng, sender.pk.data(), sender.sk.data(), + const int sent_length = create_request(mem, rng, sender.pk.data(), sender.sk.data(), packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id); ASSERT_GT(sent_length, 0); // Unpack: - const int recvd_length = handle_request(receiver.pk.data(), receiver.sk.data(), pk.data(), - incoming.data(), &recvd_pkt_id, packet.data(), sent_length); + const int recvd_length = handle_request(mem, receiver.pk.data(), receiver.sk.data(), + pk.data(), incoming.data(), &recvd_pkt_id, packet.data(), sent_length); ASSERT_GE(recvd_length, 0); EXPECT_EQ( @@ -334,7 +335,7 @@ TEST(AnnounceNodes, SetAndTest) Test_Memory mem; Test_Network ns; - Logger *log = logger_new(); + Logger *log = logger_new(mem); ASSERT_NE(log, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); ASSERT_NE(mono_time, nullptr); diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index aead975911..372b9d732e 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c @@ -204,7 +204,8 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns) #endif /* platforms */ -/** @brief Send packet to all IPv4 broadcast addresses +/** + * @brief Send packet to all IPv4 broadcast addresses * * @retval true if sent to at least one broadcast target. * @retval false on failure to find any valid broadcast target. diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index db3e193243..d4d64bcdb8 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -86,6 +86,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \ ../toxcore/ping.c \ ../toxcore/shared_key_cache.h \ ../toxcore/shared_key_cache.c \ + ../toxcore/sort.h \ + ../toxcore/sort.c \ ../toxcore/state.h \ ../toxcore/state.c \ ../toxcore/tox.h \ diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 947edef7e1..d2a84490b8 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -472,10 +472,6 @@ int m_delfriend(Messenger *m, int32_t friendnumber) return -1; } - if (m->friend_connectionstatuschange_internal != nullptr) { - m->friend_connectionstatuschange_internal(m, friendnumber, false, m->friend_connectionstatuschange_internal_userdata); - } - clear_receipts(m, friendnumber); remove_request_received(m->fr, m->friendlist[friendnumber].real_pk); friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, nullptr, @@ -775,31 +771,31 @@ int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length) } non_null() -static bool userstatus_from_int(uint8_t status, Userstatus *out) +static bool userstatus_from_int(uint8_t status, Userstatus *out_enum) { switch (status) { case USERSTATUS_NONE: { - *out = USERSTATUS_NONE; + *out_enum = USERSTATUS_NONE; return true; } case USERSTATUS_AWAY: { - *out = USERSTATUS_AWAY; + *out_enum = USERSTATUS_AWAY; return true; } case USERSTATUS_BUSY: { - *out = USERSTATUS_BUSY; + *out_enum = USERSTATUS_BUSY; return true; } case USERSTATUS_INVALID: { - *out = USERSTATUS_INVALID; + *out_enum = USERSTATUS_INVALID; return true; } default: { - *out = USERSTATUS_INVALID; + *out_enum = USERSTATUS_INVALID; return false; } } @@ -1027,13 +1023,6 @@ void m_callback_core_connection(Messenger *m, m_self_connection_status_cb *funct m->core_connection_change = function; } -void m_callback_connectionstatus_internal_av(Messenger *m, m_friend_connectionstatuschange_internal_cb *function, - void *userdata) -{ - m->friend_connectionstatuschange_internal = function; - m->friend_connectionstatuschange_internal_userdata = userdata; -} - non_null(1) nullable(3) static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber, void *userdata) { @@ -1081,11 +1070,6 @@ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, ui m->friendlist[friendnumber].status = status; check_friend_tcp_udp(m, friendnumber, userdata); - - if (m->friend_connectionstatuschange_internal != nullptr) { - m->friend_connectionstatuschange_internal(m, friendnumber, is_online, - m->friend_connectionstatuschange_internal_userdata); - } } } @@ -1855,23 +1839,6 @@ static int handle_filecontrol(Messenger *m, int32_t friendnumber, bool outbound, } } -/** @brief Set the callback for msi packets. */ -void m_callback_msi_packet(Messenger *m, m_msi_packet_cb *function, void *userdata) -{ - m->msi_packet = function; - m->msi_packet_userdata = userdata; -} - -/** @brief Send an msi packet. - * - * @retval true on success - * @retval false on failure - */ -bool m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) -{ - return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, false); -} - static int m_handle_lossy_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) { @@ -1881,17 +1848,6 @@ static int m_handle_lossy_packet(void *object, int friendcon_id, const uint8_t * return 1; } - if (data[0] <= PACKET_ID_RANGE_LOSSY_AV_END) { - const RTP_Packet_Handler *const ph = - &m->friendlist[friendcon_id].lossy_rtp_packethandlers[data[0] % PACKET_ID_RANGE_LOSSY_AV_SIZE]; - - if (ph->function != nullptr) { - return ph->function(m, friendcon_id, data, length, ph->object); - } - - return 1; - } - if (m->lossy_packethandler != nullptr) { m->lossy_packethandler(m, friendcon_id, data[0], data, length, userdata); } @@ -1904,38 +1860,6 @@ void custom_lossy_packet_registerhandler(Messenger *m, m_friend_lossy_packet_cb m->lossy_packethandler = lossy_packethandler; } -int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, m_lossy_rtp_packet_cb *function, - void *object) -{ - if (!m_friend_exists(m, friendnumber)) { - return -1; - } - - if (byte < PACKET_ID_RANGE_LOSSY_AV_START || byte > PACKET_ID_RANGE_LOSSY_AV_END) { - return -1; - } - - m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_ID_RANGE_LOSSY_AV_SIZE].function = function; - m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_ID_RANGE_LOSSY_AV_SIZE].object = object; - return 0; -} - -/** @brief High level function to send custom lossy packets. - * - * TODO(oxij): this name is confusing, because this function sends both av and custom lossy packets. - * Meanwhile, m_handle_lossy_packet routes custom packets to custom_lossy_packet_registerhandler - * as you would expect from its name. - * - * I.e. custom_lossy_packet_registerhandler's "custom lossy packet" and this "custom lossy packet" - * are not the same set of packets. - * - * @retval -1 if friend invalid. - * @retval -2 if length wrong. - * @retval -3 if first byte invalid. - * @retval -4 if friend offline. - * @retval -5 if packet failed to send because of other error. - * @retval 0 on success. - */ int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length) { if (!m_friend_exists(m, friendnumber)) { @@ -1946,7 +1870,6 @@ int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const u return -2; } - // TODO(oxij): send_lossy_cryptpacket makes this check already, similarly for other similar places if (data[0] < PACKET_ID_RANGE_LOSSY_START || data[0] > PACKET_ID_RANGE_LOSSY_END) { return -3; } @@ -1974,7 +1897,10 @@ static int handle_custom_lossless_packet(void *object, int friend_num, const uin } if (packet[0] < PACKET_ID_RANGE_LOSSLESS_CUSTOM_START || packet[0] > PACKET_ID_RANGE_LOSSLESS_CUSTOM_END) { - return -1; + // allow PACKET_ID_MSI packets to be handled by custom packet handler + if (packet[0] != PACKET_ID_MSI) { + return -1; + } } if (m->lossless_packethandler != nullptr) { @@ -2356,20 +2282,6 @@ static int m_handle_packet_file_data(Messenger *m, const int friendcon_id, const return 0; } -non_null(1, 3) nullable(5) -static int m_handle_packet_msi(Messenger *m, const int friendcon_id, const uint8_t *data, const uint16_t data_length, void *userdata) -{ - if (data_length == 0) { - return 0; - } - - if (m->msi_packet != nullptr) { - m->msi_packet(m, friendcon_id, data, data_length, m->msi_packet_userdata); - } - - return 0; -} - non_null(1, 3) nullable(5) static int m_handle_packet_invite_groupchat(Messenger *m, const int friendcon_id, const uint8_t *data, const uint16_t data_length, void *userdata) { @@ -2443,7 +2355,7 @@ static int m_handle_packet(void *object, int friendcon_id, const uint8_t *data, case PACKET_ID_FILE_DATA: return m_handle_packet_file_data(m, friendcon_id, payload, payload_length, userdata); case PACKET_ID_MSI: - return m_handle_packet_msi(m, friendcon_id, payload, payload_length, userdata); + return handle_custom_lossless_packet(object, friendcon_id, data, length, userdata); case PACKET_ID_INVITE_GROUPCHAT: return m_handle_packet_invite_groupchat(m, friendcon_id, payload, payload_length, userdata); } @@ -2468,14 +2380,12 @@ static void do_friends(Messenger *m, void *userdata) } } - if (m->friendlist[i].status == FRIEND_REQUESTED - || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */ - if (m->friendlist[i].status == FRIEND_REQUESTED) { - /* If we didn't connect to friend after successfully sending him a friend request the request is deemed - * unsuccessful so we set the status back to FRIEND_ADDED and try again. - */ - check_friend_request_timed_out(m, i, temp_time, userdata); - } + if (m->friendlist[i].status == FRIEND_REQUESTED) { + /* If we didn't connect to friend after successfully sending him a friend + * request the request is deemed unsuccessful so we set the status back to + * FRIEND_ADDED and try again. + */ + check_friend_request_timed_out(m, i, temp_time, userdata); } if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ @@ -3572,7 +3482,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random * return nullptr; } - m->log = logger_new(); + m->log = logger_new(mem); if (m->log == nullptr) { friendreq_kill(m->fr); diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index cace3340b2..be6fb5f804 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -86,6 +86,8 @@ typedef struct Messenger_Options { Messenger_State_Plugin *state_plugins; uint8_t state_plugins_length; + + bool dns_enabled; } Messenger_Options; struct Receipts { @@ -200,20 +202,10 @@ typedef void m_friend_lossy_packet_cb(Messenger *m, uint32_t friend_number, uint size_t length, void *user_data); typedef void m_friend_lossless_packet_cb(Messenger *m, uint32_t friend_number, uint8_t packet_id, const uint8_t *data, size_t length, void *user_data); -typedef void m_friend_connectionstatuschange_internal_cb(Messenger *m, uint32_t friend_number, - bool is_online, void *user_data); typedef void m_conference_invite_cb(Messenger *m, uint32_t friend_number, const uint8_t *cookie, uint16_t length, void *user_data); typedef void m_group_invite_cb(const Messenger *m, uint32_t friend_number, const uint8_t *invite_data, size_t length, const uint8_t *group_name, size_t group_name_length, void *user_data); -typedef void m_msi_packet_cb(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, - void *user_data); -typedef int m_lossy_rtp_packet_cb(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object); - -typedef struct RTP_Packet_Handler { - m_lossy_rtp_packet_cb *function; - void *object; -} RTP_Packet_Handler; typedef struct Friend { uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; @@ -243,8 +235,6 @@ typedef struct Friend { uint32_t num_sending_files; struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; - RTP_Packet_Handler lossy_rtp_packethandlers[PACKET_ID_RANGE_LOSSY_AV_SIZE]; - struct Receipts *receipts_start; struct Receipts *receipts_end; } Friend; @@ -301,8 +291,6 @@ struct Messenger { m_friend_typing_cb *friend_typingchange; m_friend_read_receipt_cb *read_receipt; m_friend_connection_status_cb *friend_connectionstatuschange; - m_friend_connectionstatuschange_internal_cb *friend_connectionstatuschange_internal; - void *friend_connectionstatuschange_internal_userdata; struct Group_Chats *conferences_object; m_conference_invite_cb *conference_invite; @@ -314,9 +302,6 @@ struct Messenger { m_file_recv_chunk_cb *file_filedata; m_file_chunk_request_cb *file_reqchunk; - m_msi_packet_cb *msi_packet; - void *msi_packet_userdata; - m_friend_lossy_packet_cb *lossy_packethandler; m_friend_lossless_packet_cb *lossless_packethandler; @@ -614,10 +599,6 @@ non_null() void m_callback_read_receipt(Messenger *m, m_friend_read_receipt_cb * */ non_null() void m_callback_connectionstatus(Messenger *m, m_friend_connection_status_cb *function); -/** Same as previous but for internal A/V core usage only */ -non_null() void m_callback_connectionstatus_internal_av( - Messenger *m, m_friend_connectionstatuschange_internal_cb *function, void *userdata); - /** @brief Set the callback for typing changes. */ non_null() void m_callback_core_connection(Messenger *m, m_self_connection_status_cb *function); @@ -731,42 +712,12 @@ non_null(1) nullable(5) int send_file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, uint16_t length); -/*** A/V related */ - -/** @brief Set the callback for msi packets. */ -non_null(1) nullable(2, 3) -void m_callback_msi_packet(Messenger *m, m_msi_packet_cb *function, void *userdata); - -/** @brief Send an msi packet. - * - * @retval true on success - * @retval false on failure - */ -non_null() -bool m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); - -/** @brief Set handlers for lossy rtp packets. - * - * @retval -1 on failure. - * @retval 0 on success. - */ -non_null(1) nullable(4, 5) -int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, - m_lossy_rtp_packet_cb *function, void *object); - /*** CUSTOM PACKETS */ /** @brief Set handlers for custom lossy packets. */ non_null() void custom_lossy_packet_registerhandler(Messenger *m, m_friend_lossy_packet_cb *lossy_packethandler); /** @brief High level function to send custom lossy packets. - * - * TODO(oxij): this name is confusing, because this function sends both av and custom lossy packets. - * Meanwhile, m_handle_lossy_packet routes custom packets to custom_lossy_packet_registerhandler - * as you would expect from its name. - * - * I.e. custom_lossy_packet_registerhandler's "custom lossy packet" and this "custom lossy packet" - * are not the same set of packets. * * @retval -1 if friend invalid. * @retval -2 if length wrong. diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 2b8c6e448f..4aaeac00e5 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -12,6 +12,11 @@ #include #include +#ifdef HAVE_LIBEV +#include +#endif + +#include "DHT.h" #include "TCP_common.h" #include "attributes.h" #include "ccompat.h" @@ -30,9 +35,19 @@ typedef struct TCP_Client_Conn { uint32_t number; } TCP_Client_Conn; +#ifdef HAVE_LIBEV +typedef struct TCP_Client_Socket_Listener { + ev_io listener; + struct ev_loop *dispatcher; +} TCP_Client_Socket_Listener; +#endif + struct TCP_Client_Connection { TCP_Connection con; TCP_Client_Status status; +#ifdef HAVE_LIBEV + TCP_Client_Socket_Listener sock_listener; +#endif uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* our public key */ uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* public key of the server */ IP_Port ip_port; /* The ip and port of the server */ @@ -85,6 +100,44 @@ TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) { return con->status; } + +#ifdef HAVE_LIBEV +non_null() +static bool tcp_con_ev_is_active(TCP_Client_Connection *con) +{ + return ev_is_active(&con->sock_listener.listener) + || ev_is_pending(&con->sock_listener.listener); +} + +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data) +{ + if (tcp_con_ev_is_active(con)) { + return; + } + + con->sock_listener.dispatcher = dispatcher; + con->sock_listener.listener.data = data; + + ev_io_init(&con->sock_listener.listener, callback, con->con.sock.sock, EV_READ); + ev_io_start(dispatcher, &con->sock_listener.listener); +} + +void tcp_con_ev_stop(TCP_Client_Connection *con) +{ + if (!tcp_con_ev_is_active(con)) { + return; + } + + ev_io_stop(con->sock_listener.dispatcher, &con->sock_listener.listener); +} +#else +Socket tcp_con_sock(const TCP_Client_Connection *con) +{ + return con->con.sock; +} +#endif + void *tcp_con_custom_object(const TCP_Client_Connection *con) { return con->custom_object; @@ -107,12 +160,12 @@ void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value) * @retval false on failure */ non_null() -static bool connect_sock_to(const Logger *logger, const Memory *mem, Socket sock, const IP_Port *ip_port, const TCP_Proxy_Info *proxy_info) +static bool connect_sock_to(const Network *ns, const Logger *logger, const Memory *mem, Socket sock, const IP_Port *ip_port, const TCP_Proxy_Info *proxy_info) { if (proxy_info->proxy_type != TCP_PROXY_NONE) { - return net_connect(mem, logger, sock, &proxy_info->ip_port); + return net_connect(ns, mem, logger, sock, &proxy_info->ip_port); } else { - return net_connect(mem, logger, sock, ip_port); + return net_connect(ns, mem, logger, sock, ip_port); } } @@ -312,7 +365,7 @@ static int generate_handshake(TCP_Client_Connection *tcp_conn) memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, tcp_conn->con.sent_nonce, CRYPTO_NONCE_SIZE); memcpy(tcp_conn->con.last_packet, tcp_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); random_nonce(tcp_conn->con.rng, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE); - const int len = encrypt_data_symmetric(tcp_conn->con.shared_key, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, + const int len = encrypt_data_symmetric(tcp_conn->con.mem, tcp_conn->con.shared_key, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, sizeof(plain), tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { @@ -334,7 +387,7 @@ non_null() static int handle_handshake(TCP_Client_Connection *tcp_conn, const uint8_t *data) { uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; - const int len = decrypt_data_symmetric(tcp_conn->con.shared_key, data, data + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(tcp_conn->con.mem, tcp_conn->con.shared_key, data, data + CRYPTO_NONCE_SIZE, TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); if (len != sizeof(plain)) { @@ -617,7 +670,7 @@ TCP_Client_Connection *new_tcp_connection( return nullptr; } - if (!(set_socket_nonblock(ns, sock) && connect_sock_to(logger, mem, sock, ip_port, proxy_info))) { + if (!(set_socket_nonblock(ns, sock) && connect_sock_to(ns, logger, mem, sock, ip_port, proxy_info))) { kill_sock(ns, sock); return nullptr; } @@ -1024,6 +1077,11 @@ void kill_tcp_connection(TCP_Client_Connection *tcp_connection) wipe_priority_list(tcp_connection->con.mem, tcp_connection->con.priority_queue_start); kill_sock(tcp_connection->con.ns, tcp_connection->con.sock); + +#ifdef HAVE_LIBEV + ev_io_stop(tcp_connection->sock_listener.dispatcher, &tcp_connection->sock_listener.listener); +#endif + crypto_memzero(tcp_connection, sizeof(TCP_Client_Connection)); mem_delete(mem, tcp_connection); } diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index ea2654b953..89f26bbcc8 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -9,6 +9,10 @@ #ifndef C_TOXCORE_TOXCORE_TCP_CLIENT_H #define C_TOXCORE_TOXCORE_TCP_CLIENT_H +#ifdef HAVE_LIBEV +#include +#endif + #include "attributes.h" #include "crypto_core.h" #include "forwarding.h" @@ -50,6 +54,20 @@ IP_Port tcp_con_ip_port(const TCP_Client_Connection *con); non_null() TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con); +// TODO(iphydf): This is exactly the same as in network.h. It should be factored +// out and probably abstracted away from ev.h. +#ifdef HAVE_LIBEV +typedef void tcp_con_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +non_null() +void tcp_con_ev_listen(TCP_Client_Connection *con, struct ev_loop *dispatcher, tcp_con_ev_listen_cb *callback, + void *data); +non_null() +void tcp_con_ev_stop(TCP_Client_Connection *con); +#else +non_null() +Socket tcp_con_sock(const TCP_Client_Connection *con); +#endif + non_null() void *tcp_con_custom_object(const TCP_Client_Connection *con); non_null() diff --git a/toxcore/TCP_common.c b/toxcore/TCP_common.c index bd3b7ca4c7..6e0ac4294a 100644 --- a/toxcore/TCP_common.c +++ b/toxcore/TCP_common.c @@ -157,7 +157,7 @@ int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con 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)); + int len = encrypt_data_symmetric(con->mem, con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (packet_size - sizeof(uint16_t))) { return -1; @@ -305,7 +305,7 @@ int read_packet_tcp_secure_connection( *next_packet_length = 0; - const int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); + const int len = decrypt_data_symmetric(mem, shared_key, recv_nonce, data_encrypted, len_packet, data); if (len + CRYPTO_MAC_SIZE != len_packet) { LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet); diff --git a/toxcore/TCP_connection.c b/toxcore/TCP_connection.c index c7161a9289..4cc61e9d86 100644 --- a/toxcore/TCP_connection.c +++ b/toxcore/TCP_connection.c @@ -71,6 +71,37 @@ uint32_t tcp_connections_count(const TCP_Connections *tcp_c) return tcp_c->tcp_connections_length; } +/** + * Return number of elements of TCP connection array. + * + * @param tcp_c struct containing TCP_con array. + * + * @return number of elements of TCP connection array. + */ +uint32_t tcp_connections_length(const TCP_Connections *tcp_c) +{ + return tcp_c->tcp_connections_length; +} + + +/** + * Return TCP connection stored at "idx" position. + * + * @param tcp_c struct containing TCP_con array. + * @param idx index of TCP connection to return (values from 0 to `tcp_connections_length() - 1`). + * + * @return TCP connection stored at "idx" position, or NULL if errors occurred. + */ +const TCP_con *tcp_connections_connection_at(const TCP_Connections *tcp_c, uint32_t idx) +{ + if (idx >= tcp_c->tcp_connections_length) { + return nullptr; + } + + return &tcp_c->tcp_connections[idx]; +} + + /** @brief Set the size of the array to num. * * @retval -1 if mem_vrealloc fails. diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h index 2d35919f10..42cdde404a 100644 --- a/toxcore/TCP_connection.h +++ b/toxcore/TCP_connection.h @@ -83,6 +83,20 @@ typedef struct TCP_Connections TCP_Connections; non_null() const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c); +non_null() +uint32_t tcp_connections_length(const TCP_Connections *tcp_c); + +/** + * Return TCP connection stored at "idx" position. + * + * @param tcp_c struct containing TCP_con array. + * @param idx index of TCP connection to return (values from 0 to `tcp_connections_length() - 1`). + * + * @return TCP connection stored at "idx" position, or NULL if errors occurred. + */ +non_null() +const TCP_con *tcp_connections_connection_at(const TCP_Connections *tcp_c, uint32_t idx); + non_null() uint32_t tcp_connections_count(const TCP_Connections *tcp_c); diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c index 1363d90220..ec686f8271 100644 --- a/toxcore/TCP_server.c +++ b/toxcore/TCP_server.c @@ -327,7 +327,7 @@ static int handle_tcp_handshake(const Logger *logger, TCP_Secure_Connection *con uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; encrypt_precompute(data, self_secret_key, shared_key); uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; - int len = decrypt_data_symmetric(shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, + int len = decrypt_data_symmetric(con->con.mem, shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain); if (len != TCP_HANDSHAKE_PLAIN_SIZE) { @@ -347,7 +347,7 @@ static int handle_tcp_handshake(const Logger *logger, TCP_Secure_Connection *con uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; random_nonce(con->con.rng, response); - len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, + len = encrypt_data_symmetric(con->con.mem, shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + CRYPTO_NONCE_SIZE); if (len != TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) { diff --git a/toxcore/announce.c b/toxcore/announce.c index b983cb0574..02a378f276 100644 --- a/toxcore/announce.c +++ b/toxcore/announce.c @@ -451,7 +451,7 @@ static int create_reply_plain_store_announce_request(Announcements *announce, return -1; } - if (decrypt_data_symmetric(shared_key, + if (decrypt_data_symmetric(announce->mem, shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, plain_len + CRYPTO_MAC_SIZE, @@ -568,7 +568,7 @@ static int create_reply(Announcements *announce, const IP_Port *source, VLA(uint8_t, plain, plain_len); const uint8_t *shared_key = dht_get_shared_key_recv(announce->dht, data + 1); - if (decrypt_data_symmetric(shared_key, + if (decrypt_data_symmetric(announce->mem, shared_key, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, plain_len + CRYPTO_MAC_SIZE, @@ -579,7 +579,7 @@ static int create_reply(Announcements *announce, const IP_Port *source, const int plain_reply_max_len = (int)reply_max_length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE); - if (plain_reply_max_len < sizeof(uint64_t)) { + if (plain_reply_max_len < (int)sizeof(uint64_t)) { return -1; } diff --git a/toxcore/bin_pack_test.cc b/toxcore/bin_pack_test.cc index 4bd8a25bfb..08e37ba549 100644 --- a/toxcore/bin_pack_test.cc +++ b/toxcore/bin_pack_test.cc @@ -32,7 +32,7 @@ TEST(BinPack, PackedUint64CanBeUnpacked) }, &orig, nullptr, buf.data(), buf.size())); - uint64_t unpacked; + uint64_t unpacked = 0; EXPECT_TRUE(bin_unpack_obj( [](void *obj, Bin_Unpack *bu) { return bin_unpack_u64_b(bu, static_cast(obj)); @@ -51,7 +51,7 @@ TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32) }, &orig, nullptr, buf.data(), buf.size())); - uint32_t unpacked; + uint32_t unpacked = 0; EXPECT_TRUE(bin_unpack_obj( [](void *obj, Bin_Unpack *bu) { return bin_unpack_u32(bu, static_cast(obj)); }, &unpacked, buf.data(), buf.size())); @@ -68,7 +68,7 @@ TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough) }, &orig, nullptr, buf.data(), buf.size())); - uint8_t unpacked; + uint8_t unpacked = 0; EXPECT_TRUE(bin_unpack_obj( [](void *obj, Bin_Unpack *bu) { return bin_unpack_u08(bu, static_cast(obj)); }, &unpacked, buf.data(), buf.size())); @@ -86,7 +86,7 @@ TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8) }, &orig, nullptr, buf.data(), buf.size())); - uint8_t unpacked; + uint8_t unpacked = 0; EXPECT_FALSE(bin_unpack_obj( [](void *obj, Bin_Unpack *bu) { return bin_unpack_u08(bu, static_cast(obj)); }, &unpacked, buf.data(), buf.size())); diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c index 7bb5bb929f..9a460a2492 100644 --- a/toxcore/crypto_core.c +++ b/toxcore/crypto_core.c @@ -13,6 +13,7 @@ #include "attributes.h" #include "ccompat.h" +#include "mem.h" #include "util.h" static_assert(CRYPTO_PUBLIC_KEY_SIZE == crypto_box_PUBLICKEYBYTES, @@ -88,9 +89,10 @@ const uint8_t *get_chat_id(const Extended_Public_Key *key) } #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) -static uint8_t *crypto_malloc(size_t bytes) +non_null() +static uint8_t *crypto_malloc(const Memory *mem, size_t bytes) { - uint8_t *ptr = (uint8_t *)malloc(bytes); + uint8_t *ptr = (uint8_t *)mem_balloc(mem, bytes); if (ptr != nullptr) { crypto_memlock(ptr, bytes); @@ -99,15 +101,15 @@ static uint8_t *crypto_malloc(size_t bytes) return ptr; } -nullable(1) -static void crypto_free(uint8_t *ptr, size_t bytes) +non_null(1) nullable(2) +static void crypto_free(const Memory *mem, uint8_t *ptr, size_t bytes) { if (ptr != nullptr) { crypto_memzero(ptr, bytes); crypto_memunlock(ptr, bytes); } - free(ptr); + mem_delete(mem, ptr); } #endif /* !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) */ @@ -240,7 +242,8 @@ int32_t encrypt_precompute(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ } -int32_t encrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], +int32_t encrypt_data_symmetric(const Memory *mem, + const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *plain, size_t length, uint8_t *encrypted) { @@ -258,12 +261,12 @@ int32_t encrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const size_t size_temp_plain = length + crypto_box_ZEROBYTES; const size_t size_temp_encrypted = length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES; - uint8_t *temp_plain = crypto_malloc(size_temp_plain); - uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted); + uint8_t *temp_plain = crypto_malloc(mem, size_temp_plain); + uint8_t *temp_encrypted = crypto_malloc(mem, size_temp_encrypted); if (temp_plain == nullptr || temp_encrypted == nullptr) { - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); return -1; } @@ -278,22 +281,23 @@ int32_t encrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, shared_key) != 0) { - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); return -1; } // Unpad the encrypted message. memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ assert(length < INT32_MAX - crypto_box_MACBYTES); return (int32_t)(length + crypto_box_MACBYTES); } -int32_t decrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], +int32_t decrypt_data_symmetric(const Memory *mem, + const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *encrypted, size_t length, uint8_t *plain) { @@ -310,12 +314,12 @@ int32_t decrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const size_t size_temp_plain = length + crypto_box_ZEROBYTES; const size_t size_temp_encrypted = length + crypto_box_BOXZEROBYTES; - uint8_t *temp_plain = crypto_malloc(size_temp_plain); - uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted); + uint8_t *temp_plain = crypto_malloc(mem, size_temp_plain); + uint8_t *temp_encrypted = crypto_malloc(mem, size_temp_encrypted); if (temp_plain == nullptr || temp_encrypted == nullptr) { - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); return -1; } @@ -330,22 +334,23 @@ int32_t decrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, shared_key) != 0) { - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); return -1; } memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); - crypto_free(temp_plain, size_temp_plain); - crypto_free(temp_encrypted, size_temp_encrypted); + crypto_free(mem, temp_plain, size_temp_plain); + crypto_free(mem, temp_encrypted, size_temp_encrypted); #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ assert(length > crypto_box_MACBYTES); assert(length < INT32_MAX); return (int32_t)(length - crypto_box_MACBYTES); } -int32_t encrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], +int32_t encrypt_data(const Memory *mem, + const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *plain, size_t length, uint8_t *encrypted) @@ -356,12 +361,13 @@ int32_t encrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], uint8_t k[crypto_box_BEFORENMBYTES]; encrypt_precompute(public_key, secret_key, k); - const int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted); + const int ret = encrypt_data_symmetric(mem, k, nonce, plain, length, encrypted); crypto_memzero(k, sizeof(k)); return ret; } -int32_t decrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], +int32_t decrypt_data(const Memory *mem, + const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *encrypted, size_t length, uint8_t *plain) @@ -372,7 +378,7 @@ int32_t decrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], uint8_t k[crypto_box_BEFORENMBYTES]; encrypt_precompute(public_key, secret_key, k); - const int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain); + const int ret = decrypt_data_symmetric(mem, k, nonce, encrypted, length, plain); crypto_memzero(k, sizeof(k)); return ret; } diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h index 979791bd97..3d405ede7f 100644 --- a/toxcore/crypto_core.h +++ b/toxcore/crypto_core.h @@ -16,6 +16,7 @@ #include #include "attributes.h" +#include "mem.h" #ifdef __cplusplus extern "C" { @@ -386,7 +387,8 @@ void crypto_derive_public_key(uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], * @return length of encrypted data if everything was fine. */ non_null() -int32_t encrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], +int32_t encrypt_data(const Memory *mem, + const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *plain, size_t length, uint8_t *encrypted); @@ -403,7 +405,8 @@ int32_t encrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], * @return length of plain text data if everything was fine. */ non_null() -int32_t decrypt_data(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], +int32_t decrypt_data(const Memory *mem, + const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *encrypted, size_t length, uint8_t *plain); @@ -431,7 +434,8 @@ int32_t encrypt_precompute(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], * @return length of encrypted data if everything was fine. */ non_null() -int32_t encrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], +int32_t encrypt_data_symmetric(const Memory *mem, + const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *plain, size_t length, uint8_t *encrypted); @@ -446,7 +450,8 @@ int32_t encrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], * @return length of plain data if everything was fine. */ non_null() -int32_t decrypt_data_symmetric(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], +int32_t decrypt_data_symmetric(const Memory *mem, + const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE], const uint8_t *encrypted, size_t length, uint8_t *plain); diff --git a/toxcore/crypto_core_test.cc b/toxcore/crypto_core_test.cc index d18ae2daab..6203afbce5 100644 --- a/toxcore/crypto_core_test.cc +++ b/toxcore/crypto_core_test.cc @@ -7,6 +7,7 @@ #include #include "crypto_core_test_util.hh" +#include "mem_test_util.hh" #include "util.h" namespace { @@ -17,8 +18,38 @@ using SecretKey = std::array; using Signature = std::array; using Nonce = std::array; +TEST(PkEqual, TwoRandomIdsAreNotEqual) +{ + std::mt19937 rng; + std::uniform_int_distribution dist{0, UINT8_MAX}; + + uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE]; + + std::generate(std::begin(pk1), std::end(pk1), [&]() { return dist(rng); }); + std::generate(std::begin(pk2), std::end(pk2), [&]() { return dist(rng); }); + + EXPECT_FALSE(pk_equal(pk1, pk2)); +} + +TEST(PkEqual, IdCopyMakesKeysEqual) +{ + std::mt19937 rng; + std::uniform_int_distribution dist{0, UINT8_MAX}; + + uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE] = {0}; + + std::generate(std::begin(pk1), std::end(pk1), [&]() { return dist(rng); }); + + pk_copy(pk2, pk1); + + EXPECT_TRUE(pk_equal(pk1, pk2)); +} + TEST(CryptoCore, EncryptLargeData) { + Test_Memory mem; Test_Random rng; Nonce nonce{}; @@ -30,7 +61,8 @@ TEST(CryptoCore, EncryptLargeData) std::vector plain(100 * 1024 * 1024); std::vector encrypted(plain.size() + CRYPTO_MAC_SIZE); - encrypt_data(pk.data(), sk.data(), nonce.data(), plain.data(), plain.size(), encrypted.data()); + encrypt_data( + mem, pk.data(), sk.data(), nonce.data(), plain.data(), plain.size(), encrypted.data()); } TEST(CryptoCore, IncrementNonce) diff --git a/toxcore/events/conference_connected.c b/toxcore/events/conference_connected.c index dbd9e4b51a..8aeb17204b 100644 --- a/toxcore/events/conference_connected.c +++ b/toxcore/events/conference_connected.c @@ -109,7 +109,10 @@ static Tox_Event_Conference_Connected *tox_events_add_conference_connected(Tox_E event.type = TOX_EVENT_CONFERENCE_CONNECTED; event.data.conference_connected = conference_connected; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_connected_free(conference_connected, mem); + return nullptr; + } return conference_connected; } diff --git a/toxcore/events/conference_invite.c b/toxcore/events/conference_invite.c index fb1f794bf3..c9b8d14bc1 100644 --- a/toxcore/events/conference_invite.c +++ b/toxcore/events/conference_invite.c @@ -177,7 +177,10 @@ static Tox_Event_Conference_Invite *tox_events_add_conference_invite(Tox_Events event.type = TOX_EVENT_CONFERENCE_INVITE; event.data.conference_invite = conference_invite; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_invite_free(conference_invite, mem); + return nullptr; + } return conference_invite; } diff --git a/toxcore/events/conference_message.c b/toxcore/events/conference_message.c index 74e1123e01..e509827e45 100644 --- a/toxcore/events/conference_message.c +++ b/toxcore/events/conference_message.c @@ -193,7 +193,10 @@ static Tox_Event_Conference_Message *tox_events_add_conference_message(Tox_Event event.type = TOX_EVENT_CONFERENCE_MESSAGE; event.data.conference_message = conference_message; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_message_free(conference_message, mem); + return nullptr; + } return conference_message; } diff --git a/toxcore/events/conference_peer_list_changed.c b/toxcore/events/conference_peer_list_changed.c index 050bfb08f8..f7efd3f806 100644 --- a/toxcore/events/conference_peer_list_changed.c +++ b/toxcore/events/conference_peer_list_changed.c @@ -109,7 +109,10 @@ static Tox_Event_Conference_Peer_List_Changed *tox_events_add_conference_peer_li event.type = TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED; event.data.conference_peer_list_changed = conference_peer_list_changed; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_peer_list_changed_free(conference_peer_list_changed, mem); + return nullptr; + } return conference_peer_list_changed; } diff --git a/toxcore/events/conference_peer_name.c b/toxcore/events/conference_peer_name.c index fc6c255791..930065631f 100644 --- a/toxcore/events/conference_peer_name.c +++ b/toxcore/events/conference_peer_name.c @@ -175,7 +175,10 @@ static Tox_Event_Conference_Peer_Name *tox_events_add_conference_peer_name(Tox_E event.type = TOX_EVENT_CONFERENCE_PEER_NAME; event.data.conference_peer_name = conference_peer_name; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_peer_name_free(conference_peer_name, mem); + return nullptr; + } return conference_peer_name; } diff --git a/toxcore/events/conference_title.c b/toxcore/events/conference_title.c index d761f51285..d8e269032e 100644 --- a/toxcore/events/conference_title.c +++ b/toxcore/events/conference_title.c @@ -175,7 +175,10 @@ static Tox_Event_Conference_Title *tox_events_add_conference_title(Tox_Events *e event.type = TOX_EVENT_CONFERENCE_TITLE; event.data.conference_title = conference_title; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_conference_title_free(conference_title, mem); + return nullptr; + } return conference_title; } diff --git a/toxcore/events/dht_get_nodes_response.c b/toxcore/events/dht_get_nodes_response.c index 6e03b73ea4..f637b9c93a 100644 --- a/toxcore/events/dht_get_nodes_response.c +++ b/toxcore/events/dht_get_nodes_response.c @@ -158,7 +158,10 @@ static Tox_Event_Dht_Get_Nodes_Response *tox_events_add_dht_get_nodes_response(T event.type = TOX_EVENT_DHT_GET_NODES_RESPONSE; event.data.dht_get_nodes_response = dht_get_nodes_response; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_dht_get_nodes_response_free(dht_get_nodes_response, mem); + return nullptr; + } return dht_get_nodes_response; } diff --git a/toxcore/events/file_chunk_request.c b/toxcore/events/file_chunk_request.c index 4117ef3c4b..23e5f5bf18 100644 --- a/toxcore/events/file_chunk_request.c +++ b/toxcore/events/file_chunk_request.c @@ -162,7 +162,10 @@ static Tox_Event_File_Chunk_Request *tox_events_add_file_chunk_request(Tox_Event event.type = TOX_EVENT_FILE_CHUNK_REQUEST; event.data.file_chunk_request = file_chunk_request; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_file_chunk_request_free(file_chunk_request, mem); + return nullptr; + } return file_chunk_request; } diff --git a/toxcore/events/file_recv.c b/toxcore/events/file_recv.c index 45cec44b0d..389ce59830 100644 --- a/toxcore/events/file_recv.c +++ b/toxcore/events/file_recv.c @@ -207,7 +207,10 @@ static Tox_Event_File_Recv *tox_events_add_file_recv(Tox_Events *events, const M event.type = TOX_EVENT_FILE_RECV; event.data.file_recv = file_recv; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_file_recv_free(file_recv, mem); + return nullptr; + } return file_recv; } diff --git a/toxcore/events/file_recv_chunk.c b/toxcore/events/file_recv_chunk.c index 2edf7c5a7b..619011a4af 100644 --- a/toxcore/events/file_recv_chunk.c +++ b/toxcore/events/file_recv_chunk.c @@ -191,7 +191,10 @@ static Tox_Event_File_Recv_Chunk *tox_events_add_file_recv_chunk(Tox_Events *eve event.type = TOX_EVENT_FILE_RECV_CHUNK; event.data.file_recv_chunk = file_recv_chunk; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_file_recv_chunk_free(file_recv_chunk, mem); + return nullptr; + } return file_recv_chunk; } diff --git a/toxcore/events/file_recv_control.c b/toxcore/events/file_recv_control.c index 14a34aaf3b..3c575c09a6 100644 --- a/toxcore/events/file_recv_control.c +++ b/toxcore/events/file_recv_control.c @@ -148,7 +148,10 @@ static Tox_Event_File_Recv_Control *tox_events_add_file_recv_control(Tox_Events event.type = TOX_EVENT_FILE_RECV_CONTROL; event.data.file_recv_control = file_recv_control; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_file_recv_control_free(file_recv_control, mem); + return nullptr; + } return file_recv_control; } diff --git a/toxcore/events/friend_connection_status.c b/toxcore/events/friend_connection_status.c index 330554b05e..68c48695ad 100644 --- a/toxcore/events/friend_connection_status.c +++ b/toxcore/events/friend_connection_status.c @@ -132,7 +132,10 @@ static Tox_Event_Friend_Connection_Status *tox_events_add_friend_connection_stat event.type = TOX_EVENT_FRIEND_CONNECTION_STATUS; event.data.friend_connection_status = friend_connection_status; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_connection_status_free(friend_connection_status, mem); + return nullptr; + } return friend_connection_status; } diff --git a/toxcore/events/friend_lossless_packet.c b/toxcore/events/friend_lossless_packet.c index 17e8fad926..b783e332f0 100644 --- a/toxcore/events/friend_lossless_packet.c +++ b/toxcore/events/friend_lossless_packet.c @@ -159,7 +159,10 @@ static Tox_Event_Friend_Lossless_Packet *tox_events_add_friend_lossless_packet(T event.type = TOX_EVENT_FRIEND_LOSSLESS_PACKET; event.data.friend_lossless_packet = friend_lossless_packet; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_lossless_packet_free(friend_lossless_packet, mem); + return nullptr; + } return friend_lossless_packet; } diff --git a/toxcore/events/friend_lossy_packet.c b/toxcore/events/friend_lossy_packet.c index 6b2e9ed2b0..e3a6ad5f59 100644 --- a/toxcore/events/friend_lossy_packet.c +++ b/toxcore/events/friend_lossy_packet.c @@ -159,7 +159,10 @@ static Tox_Event_Friend_Lossy_Packet *tox_events_add_friend_lossy_packet(Tox_Eve event.type = TOX_EVENT_FRIEND_LOSSY_PACKET; event.data.friend_lossy_packet = friend_lossy_packet; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_lossy_packet_free(friend_lossy_packet, mem); + return nullptr; + } return friend_lossy_packet; } diff --git a/toxcore/events/friend_message.c b/toxcore/events/friend_message.c index befcc74a24..dfd1daea39 100644 --- a/toxcore/events/friend_message.c +++ b/toxcore/events/friend_message.c @@ -177,7 +177,10 @@ static Tox_Event_Friend_Message *tox_events_add_friend_message(Tox_Events *event event.type = TOX_EVENT_FRIEND_MESSAGE; event.data.friend_message = friend_message; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_message_free(friend_message, mem); + return nullptr; + } return friend_message; } diff --git a/toxcore/events/friend_name.c b/toxcore/events/friend_name.c index dfa9b39608..b5a5129724 100644 --- a/toxcore/events/friend_name.c +++ b/toxcore/events/friend_name.c @@ -159,7 +159,10 @@ static Tox_Event_Friend_Name *tox_events_add_friend_name(Tox_Events *events, con event.type = TOX_EVENT_FRIEND_NAME; event.data.friend_name = friend_name; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_name_free(friend_name, mem); + return nullptr; + } return friend_name; } diff --git a/toxcore/events/friend_read_receipt.c b/toxcore/events/friend_read_receipt.c index e5f2f9db52..88808b5825 100644 --- a/toxcore/events/friend_read_receipt.c +++ b/toxcore/events/friend_read_receipt.c @@ -130,7 +130,10 @@ static Tox_Event_Friend_Read_Receipt *tox_events_add_friend_read_receipt(Tox_Eve event.type = TOX_EVENT_FRIEND_READ_RECEIPT; event.data.friend_read_receipt = friend_read_receipt; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_read_receipt_free(friend_read_receipt, mem); + return nullptr; + } return friend_read_receipt; } diff --git a/toxcore/events/friend_request.c b/toxcore/events/friend_request.c index b492c15147..6cd8ac66c7 100644 --- a/toxcore/events/friend_request.c +++ b/toxcore/events/friend_request.c @@ -152,7 +152,10 @@ static Tox_Event_Friend_Request *tox_events_add_friend_request(Tox_Events *event event.type = TOX_EVENT_FRIEND_REQUEST; event.data.friend_request = friend_request; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_request_free(friend_request, mem); + return nullptr; + } return friend_request; } diff --git a/toxcore/events/friend_status.c b/toxcore/events/friend_status.c index 3d7499722b..5af2d451d7 100644 --- a/toxcore/events/friend_status.c +++ b/toxcore/events/friend_status.c @@ -132,7 +132,10 @@ static Tox_Event_Friend_Status *tox_events_add_friend_status(Tox_Events *events, event.type = TOX_EVENT_FRIEND_STATUS; event.data.friend_status = friend_status; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_status_free(friend_status, mem); + return nullptr; + } return friend_status; } diff --git a/toxcore/events/friend_status_message.c b/toxcore/events/friend_status_message.c index ad0519911e..178342f292 100644 --- a/toxcore/events/friend_status_message.c +++ b/toxcore/events/friend_status_message.c @@ -159,7 +159,10 @@ static Tox_Event_Friend_Status_Message *tox_events_add_friend_status_message(Tox event.type = TOX_EVENT_FRIEND_STATUS_MESSAGE; event.data.friend_status_message = friend_status_message; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_status_message_free(friend_status_message, mem); + return nullptr; + } return friend_status_message; } diff --git a/toxcore/events/friend_typing.c b/toxcore/events/friend_typing.c index 692b07fb88..96c719570f 100644 --- a/toxcore/events/friend_typing.c +++ b/toxcore/events/friend_typing.c @@ -130,7 +130,10 @@ static Tox_Event_Friend_Typing *tox_events_add_friend_typing(Tox_Events *events, event.type = TOX_EVENT_FRIEND_TYPING; event.data.friend_typing = friend_typing; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_friend_typing_free(friend_typing, mem); + return nullptr; + } return friend_typing; } diff --git a/toxcore/events/group_custom_packet.c b/toxcore/events/group_custom_packet.c index a82e2c3a6c..eb4d49d594 100644 --- a/toxcore/events/group_custom_packet.c +++ b/toxcore/events/group_custom_packet.c @@ -175,7 +175,10 @@ static Tox_Event_Group_Custom_Packet *tox_events_add_group_custom_packet(Tox_Eve event.type = TOX_EVENT_GROUP_CUSTOM_PACKET; event.data.group_custom_packet = group_custom_packet; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_custom_packet_free(group_custom_packet, mem); + return nullptr; + } return group_custom_packet; } @@ -220,7 +223,7 @@ static Tox_Event_Group_Custom_Packet *tox_event_group_custom_packet_alloc(void * *****************************************************/ void tox_events_handle_group_custom_packet( - Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length, + Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t data_length, void *user_data) { Tox_Event_Group_Custom_Packet *group_custom_packet = tox_event_group_custom_packet_alloc(user_data); @@ -231,5 +234,5 @@ void tox_events_handle_group_custom_packet( tox_event_group_custom_packet_set_group_number(group_custom_packet, group_number); tox_event_group_custom_packet_set_peer_id(group_custom_packet, peer_id); - tox_event_group_custom_packet_set_data(group_custom_packet, data, length); + tox_event_group_custom_packet_set_data(group_custom_packet, data, data_length); } diff --git a/toxcore/events/group_custom_private_packet.c b/toxcore/events/group_custom_private_packet.c index 56282f0fb8..f7c1634120 100644 --- a/toxcore/events/group_custom_private_packet.c +++ b/toxcore/events/group_custom_private_packet.c @@ -175,7 +175,10 @@ static Tox_Event_Group_Custom_Private_Packet *tox_events_add_group_custom_privat event.type = TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET; event.data.group_custom_private_packet = group_custom_private_packet; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_custom_private_packet_free(group_custom_private_packet, mem); + return nullptr; + } return group_custom_private_packet; } @@ -220,7 +223,7 @@ static Tox_Event_Group_Custom_Private_Packet *tox_event_group_custom_private_pac *****************************************************/ void tox_events_handle_group_custom_private_packet( - Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length, + Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t data_length, void *user_data) { Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet = tox_event_group_custom_private_packet_alloc(user_data); @@ -231,5 +234,5 @@ void tox_events_handle_group_custom_private_packet( tox_event_group_custom_private_packet_set_group_number(group_custom_private_packet, group_number); tox_event_group_custom_private_packet_set_peer_id(group_custom_private_packet, peer_id); - tox_event_group_custom_private_packet_set_data(group_custom_private_packet, data, length); + tox_event_group_custom_private_packet_set_data(group_custom_private_packet, data, data_length); } diff --git a/toxcore/events/group_invite.c b/toxcore/events/group_invite.c index 0691dcd1fe..6372eb598c 100644 --- a/toxcore/events/group_invite.c +++ b/toxcore/events/group_invite.c @@ -203,7 +203,10 @@ static Tox_Event_Group_Invite *tox_events_add_group_invite(Tox_Events *events, c event.type = TOX_EVENT_GROUP_INVITE; event.data.group_invite = group_invite; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_invite_free(group_invite, mem); + return nullptr; + } return group_invite; } @@ -248,7 +251,7 @@ static Tox_Event_Group_Invite *tox_event_group_invite_alloc(void *user_data) *****************************************************/ void tox_events_handle_group_invite( - Tox *tox, uint32_t friend_number, const uint8_t *invite_data, size_t length, const uint8_t *group_name, size_t group_name_length, + Tox *tox, uint32_t friend_number, const uint8_t *invite_data, size_t invite_data_length, const uint8_t *group_name, size_t group_name_length, void *user_data) { Tox_Event_Group_Invite *group_invite = tox_event_group_invite_alloc(user_data); @@ -258,6 +261,6 @@ void tox_events_handle_group_invite( } tox_event_group_invite_set_friend_number(group_invite, friend_number); - tox_event_group_invite_set_invite_data(group_invite, invite_data, length); + tox_event_group_invite_set_invite_data(group_invite, invite_data, invite_data_length); tox_event_group_invite_set_group_name(group_invite, group_name, group_name_length); } diff --git a/toxcore/events/group_join_fail.c b/toxcore/events/group_join_fail.c index b85896858b..7b95454b84 100644 --- a/toxcore/events/group_join_fail.c +++ b/toxcore/events/group_join_fail.c @@ -132,7 +132,10 @@ static Tox_Event_Group_Join_Fail *tox_events_add_group_join_fail(Tox_Events *eve event.type = TOX_EVENT_GROUP_JOIN_FAIL; event.data.group_join_fail = group_join_fail; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_join_fail_free(group_join_fail, mem); + return nullptr; + } return group_join_fail; } diff --git a/toxcore/events/group_message.c b/toxcore/events/group_message.c index a200f84566..9ed07e43a6 100644 --- a/toxcore/events/group_message.c +++ b/toxcore/events/group_message.c @@ -27,7 +27,7 @@ struct Tox_Event_Group_Message { uint32_t group_number; uint32_t peer_id; - Tox_Message_Type type; + Tox_Message_Type message_type; uint8_t *message; uint32_t message_length; uint32_t message_id; @@ -60,16 +60,16 @@ uint32_t tox_event_group_message_get_peer_id(const Tox_Event_Group_Message *grou } non_null() -static void tox_event_group_message_set_type(Tox_Event_Group_Message *group_message, - Tox_Message_Type type) +static void tox_event_group_message_set_message_type(Tox_Event_Group_Message *group_message, + Tox_Message_Type message_type) { assert(group_message != nullptr); - group_message->type = type; + group_message->message_type = message_type; } -Tox_Message_Type tox_event_group_message_get_type(const Tox_Event_Group_Message *group_message) +Tox_Message_Type tox_event_group_message_get_message_type(const Tox_Event_Group_Message *group_message) { assert(group_message != nullptr); - return group_message->type; + return group_message->message_type; } non_null(1) nullable(2) @@ -143,7 +143,7 @@ bool tox_event_group_message_pack( return bin_pack_array(bp, 5) && bin_pack_u32(bp, event->group_number) && bin_pack_u32(bp, event->peer_id) - && tox_message_type_pack(event->type, bp) + && tox_message_type_pack(event->message_type, bp) && bin_pack_bin(bp, event->message, event->message_length) && bin_pack_u32(bp, event->message_id); } @@ -159,7 +159,7 @@ static bool tox_event_group_message_unpack_into( return bin_unpack_u32(bu, &event->group_number) && bin_unpack_u32(bu, &event->peer_id) - && tox_message_type_unpack(&event->type, bu) + && tox_message_type_unpack(&event->message_type, bu) && bin_unpack_bin(bu, &event->message, &event->message_length) && bin_unpack_u32(bu, &event->message_id); } @@ -209,7 +209,10 @@ static Tox_Event_Group_Message *tox_events_add_group_message(Tox_Events *events, event.type = TOX_EVENT_GROUP_MESSAGE; event.data.group_message = group_message; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_message_free(group_message, mem); + return nullptr; + } return group_message; } @@ -254,7 +257,7 @@ static Tox_Event_Group_Message *tox_event_group_message_alloc(void *user_data) *****************************************************/ void tox_events_handle_group_message( - Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type type, const uint8_t *message, size_t length, uint32_t message_id, + Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type message_type, const uint8_t *message, size_t message_length, uint32_t message_id, void *user_data) { Tox_Event_Group_Message *group_message = tox_event_group_message_alloc(user_data); @@ -265,7 +268,7 @@ void tox_events_handle_group_message( tox_event_group_message_set_group_number(group_message, group_number); tox_event_group_message_set_peer_id(group_message, peer_id); - tox_event_group_message_set_type(group_message, type); - tox_event_group_message_set_message(group_message, message, length); + tox_event_group_message_set_message_type(group_message, message_type); + tox_event_group_message_set_message(group_message, message, message_length); tox_event_group_message_set_message_id(group_message, message_id); } diff --git a/toxcore/events/group_moderation.c b/toxcore/events/group_moderation.c index ba510d5b2a..eb8d3ba41e 100644 --- a/toxcore/events/group_moderation.c +++ b/toxcore/events/group_moderation.c @@ -164,7 +164,10 @@ static Tox_Event_Group_Moderation *tox_events_add_group_moderation(Tox_Events *e event.type = TOX_EVENT_GROUP_MODERATION; event.data.group_moderation = group_moderation; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_moderation_free(group_moderation, mem); + return nullptr; + } return group_moderation; } diff --git a/toxcore/events/group_password.c b/toxcore/events/group_password.c index ad6e86b9d3..14bda0f766 100644 --- a/toxcore/events/group_password.c +++ b/toxcore/events/group_password.c @@ -159,7 +159,10 @@ static Tox_Event_Group_Password *tox_events_add_group_password(Tox_Events *event event.type = TOX_EVENT_GROUP_PASSWORD; event.data.group_password = group_password; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_password_free(group_password, mem); + return nullptr; + } return group_password; } @@ -204,7 +207,7 @@ static Tox_Event_Group_Password *tox_event_group_password_alloc(void *user_data) *****************************************************/ void tox_events_handle_group_password( - Tox *tox, uint32_t group_number, const uint8_t *password, size_t length, + Tox *tox, uint32_t group_number, const uint8_t *password, size_t password_length, void *user_data) { Tox_Event_Group_Password *group_password = tox_event_group_password_alloc(user_data); @@ -214,5 +217,5 @@ void tox_events_handle_group_password( } tox_event_group_password_set_group_number(group_password, group_number); - tox_event_group_password_set_password(group_password, password, length); + tox_event_group_password_set_password(group_password, password, password_length); } diff --git a/toxcore/events/group_peer_exit.c b/toxcore/events/group_peer_exit.c index 16d1eba7a6..405b4b6c16 100644 --- a/toxcore/events/group_peer_exit.c +++ b/toxcore/events/group_peer_exit.c @@ -237,7 +237,10 @@ static Tox_Event_Group_Peer_Exit *tox_events_add_group_peer_exit(Tox_Events *eve event.type = TOX_EVENT_GROUP_PEER_EXIT; event.data.group_peer_exit = group_peer_exit; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_peer_exit_free(group_peer_exit, mem); + return nullptr; + } return group_peer_exit; } diff --git a/toxcore/events/group_peer_join.c b/toxcore/events/group_peer_join.c index af0d006e87..8dc34befee 100644 --- a/toxcore/events/group_peer_join.c +++ b/toxcore/events/group_peer_join.c @@ -130,7 +130,10 @@ static Tox_Event_Group_Peer_Join *tox_events_add_group_peer_join(Tox_Events *eve event.type = TOX_EVENT_GROUP_PEER_JOIN; event.data.group_peer_join = group_peer_join; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_peer_join_free(group_peer_join, mem); + return nullptr; + } return group_peer_join; } diff --git a/toxcore/events/group_peer_limit.c b/toxcore/events/group_peer_limit.c index 5e2e23558c..157827c560 100644 --- a/toxcore/events/group_peer_limit.c +++ b/toxcore/events/group_peer_limit.c @@ -130,7 +130,10 @@ static Tox_Event_Group_Peer_Limit *tox_events_add_group_peer_limit(Tox_Events *e event.type = TOX_EVENT_GROUP_PEER_LIMIT; event.data.group_peer_limit = group_peer_limit; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_peer_limit_free(group_peer_limit, mem); + return nullptr; + } return group_peer_limit; } diff --git a/toxcore/events/group_peer_name.c b/toxcore/events/group_peer_name.c index f8273e94b4..063a6ab9a3 100644 --- a/toxcore/events/group_peer_name.c +++ b/toxcore/events/group_peer_name.c @@ -175,7 +175,10 @@ static Tox_Event_Group_Peer_Name *tox_events_add_group_peer_name(Tox_Events *eve event.type = TOX_EVENT_GROUP_PEER_NAME; event.data.group_peer_name = group_peer_name; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_peer_name_free(group_peer_name, mem); + return nullptr; + } return group_peer_name; } @@ -220,7 +223,7 @@ static Tox_Event_Group_Peer_Name *tox_event_group_peer_name_alloc(void *user_dat *****************************************************/ void tox_events_handle_group_peer_name( - Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t length, + Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t name_length, void *user_data) { Tox_Event_Group_Peer_Name *group_peer_name = tox_event_group_peer_name_alloc(user_data); @@ -231,5 +234,5 @@ void tox_events_handle_group_peer_name( tox_event_group_peer_name_set_group_number(group_peer_name, group_number); tox_event_group_peer_name_set_peer_id(group_peer_name, peer_id); - tox_event_group_peer_name_set_name(group_peer_name, name, length); + tox_event_group_peer_name_set_name(group_peer_name, name, name_length); } diff --git a/toxcore/events/group_peer_status.c b/toxcore/events/group_peer_status.c index 4165d90ec2..d646caec8c 100644 --- a/toxcore/events/group_peer_status.c +++ b/toxcore/events/group_peer_status.c @@ -148,7 +148,10 @@ static Tox_Event_Group_Peer_Status *tox_events_add_group_peer_status(Tox_Events event.type = TOX_EVENT_GROUP_PEER_STATUS; event.data.group_peer_status = group_peer_status; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_peer_status_free(group_peer_status, mem); + return nullptr; + } return group_peer_status; } diff --git a/toxcore/events/group_privacy_state.c b/toxcore/events/group_privacy_state.c index 1c683c255c..3fa081c20a 100644 --- a/toxcore/events/group_privacy_state.c +++ b/toxcore/events/group_privacy_state.c @@ -132,7 +132,10 @@ static Tox_Event_Group_Privacy_State *tox_events_add_group_privacy_state(Tox_Eve event.type = TOX_EVENT_GROUP_PRIVACY_STATE; event.data.group_privacy_state = group_privacy_state; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_privacy_state_free(group_privacy_state, mem); + return nullptr; + } return group_privacy_state; } diff --git a/toxcore/events/group_private_message.c b/toxcore/events/group_private_message.c index a9efdd526c..9b7f95aa3d 100644 --- a/toxcore/events/group_private_message.c +++ b/toxcore/events/group_private_message.c @@ -27,7 +27,7 @@ struct Tox_Event_Group_Private_Message { uint32_t group_number; uint32_t peer_id; - Tox_Message_Type type; + Tox_Message_Type message_type; uint8_t *message; uint32_t message_length; uint32_t message_id; @@ -60,16 +60,16 @@ uint32_t tox_event_group_private_message_get_peer_id(const Tox_Event_Group_Priva } non_null() -static void tox_event_group_private_message_set_type(Tox_Event_Group_Private_Message *group_private_message, - Tox_Message_Type type) +static void tox_event_group_private_message_set_message_type(Tox_Event_Group_Private_Message *group_private_message, + Tox_Message_Type message_type) { assert(group_private_message != nullptr); - group_private_message->type = type; + group_private_message->message_type = message_type; } -Tox_Message_Type tox_event_group_private_message_get_type(const Tox_Event_Group_Private_Message *group_private_message) +Tox_Message_Type tox_event_group_private_message_get_message_type(const Tox_Event_Group_Private_Message *group_private_message) { assert(group_private_message != nullptr); - return group_private_message->type; + return group_private_message->message_type; } non_null(1) nullable(2) @@ -143,7 +143,7 @@ bool tox_event_group_private_message_pack( return bin_pack_array(bp, 5) && bin_pack_u32(bp, event->group_number) && bin_pack_u32(bp, event->peer_id) - && tox_message_type_pack(event->type, bp) + && tox_message_type_pack(event->message_type, bp) && bin_pack_bin(bp, event->message, event->message_length) && bin_pack_u32(bp, event->message_id); } @@ -159,7 +159,7 @@ static bool tox_event_group_private_message_unpack_into( return bin_unpack_u32(bu, &event->group_number) && bin_unpack_u32(bu, &event->peer_id) - && tox_message_type_unpack(&event->type, bu) + && tox_message_type_unpack(&event->message_type, bu) && bin_unpack_bin(bu, &event->message, &event->message_length) && bin_unpack_u32(bu, &event->message_id); } @@ -209,7 +209,10 @@ static Tox_Event_Group_Private_Message *tox_events_add_group_private_message(Tox event.type = TOX_EVENT_GROUP_PRIVATE_MESSAGE; event.data.group_private_message = group_private_message; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_private_message_free(group_private_message, mem); + return nullptr; + } return group_private_message; } @@ -254,7 +257,7 @@ static Tox_Event_Group_Private_Message *tox_event_group_private_message_alloc(vo *****************************************************/ void tox_events_handle_group_private_message( - Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type type, const uint8_t *message, size_t length, uint32_t message_id, + Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Message_Type message_type, const uint8_t *message, size_t message_length, uint32_t message_id, void *user_data) { Tox_Event_Group_Private_Message *group_private_message = tox_event_group_private_message_alloc(user_data); @@ -265,7 +268,7 @@ void tox_events_handle_group_private_message( tox_event_group_private_message_set_group_number(group_private_message, group_number); tox_event_group_private_message_set_peer_id(group_private_message, peer_id); - tox_event_group_private_message_set_type(group_private_message, type); - tox_event_group_private_message_set_message(group_private_message, message, length); + tox_event_group_private_message_set_message_type(group_private_message, message_type); + tox_event_group_private_message_set_message(group_private_message, message, message_length); tox_event_group_private_message_set_message_id(group_private_message, message_id); } diff --git a/toxcore/events/group_self_join.c b/toxcore/events/group_self_join.c index 0745e975f8..6cc3080aa6 100644 --- a/toxcore/events/group_self_join.c +++ b/toxcore/events/group_self_join.c @@ -109,7 +109,10 @@ static Tox_Event_Group_Self_Join *tox_events_add_group_self_join(Tox_Events *eve event.type = TOX_EVENT_GROUP_SELF_JOIN; event.data.group_self_join = group_self_join; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_self_join_free(group_self_join, mem); + return nullptr; + } return group_self_join; } diff --git a/toxcore/events/group_topic.c b/toxcore/events/group_topic.c index 23cdd5d354..7588d43f7f 100644 --- a/toxcore/events/group_topic.c +++ b/toxcore/events/group_topic.c @@ -175,7 +175,10 @@ static Tox_Event_Group_Topic *tox_events_add_group_topic(Tox_Events *events, con event.type = TOX_EVENT_GROUP_TOPIC; event.data.group_topic = group_topic; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_topic_free(group_topic, mem); + return nullptr; + } return group_topic; } @@ -220,7 +223,7 @@ static Tox_Event_Group_Topic *tox_event_group_topic_alloc(void *user_data) *****************************************************/ void tox_events_handle_group_topic( - Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, size_t length, + Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, size_t topic_length, void *user_data) { Tox_Event_Group_Topic *group_topic = tox_event_group_topic_alloc(user_data); @@ -231,5 +234,5 @@ void tox_events_handle_group_topic( tox_event_group_topic_set_group_number(group_topic, group_number); tox_event_group_topic_set_peer_id(group_topic, peer_id); - tox_event_group_topic_set_topic(group_topic, topic, length); + tox_event_group_topic_set_topic(group_topic, topic, topic_length); } diff --git a/toxcore/events/group_topic_lock.c b/toxcore/events/group_topic_lock.c index 36fb49393a..431ff38159 100644 --- a/toxcore/events/group_topic_lock.c +++ b/toxcore/events/group_topic_lock.c @@ -132,7 +132,10 @@ static Tox_Event_Group_Topic_Lock *tox_events_add_group_topic_lock(Tox_Events *e event.type = TOX_EVENT_GROUP_TOPIC_LOCK; event.data.group_topic_lock = group_topic_lock; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_topic_lock_free(group_topic_lock, mem); + return nullptr; + } return group_topic_lock; } diff --git a/toxcore/events/group_voice_state.c b/toxcore/events/group_voice_state.c index fba0300389..d9c592b882 100644 --- a/toxcore/events/group_voice_state.c +++ b/toxcore/events/group_voice_state.c @@ -132,7 +132,10 @@ static Tox_Event_Group_Voice_State *tox_events_add_group_voice_state(Tox_Events event.type = TOX_EVENT_GROUP_VOICE_STATE; event.data.group_voice_state = group_voice_state; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_group_voice_state_free(group_voice_state, mem); + return nullptr; + } return group_voice_state; } diff --git a/toxcore/events/self_connection_status.c b/toxcore/events/self_connection_status.c index 8d8bc803ea..b79d70b408 100644 --- a/toxcore/events/self_connection_status.c +++ b/toxcore/events/self_connection_status.c @@ -111,7 +111,10 @@ static Tox_Event_Self_Connection_Status *tox_events_add_self_connection_status(T event.type = TOX_EVENT_SELF_CONNECTION_STATUS; event.data.self_connection_status = self_connection_status; - tox_events_add(events, &event); + if (!tox_events_add(events, &event)) { + tox_event_self_connection_status_free(self_connection_status, mem); + return nullptr; + } return self_connection_status; } diff --git a/toxcore/forwarding_fuzz_test.cc b/toxcore/forwarding_fuzz_test.cc index da772a197a..4b8521ab07 100644 --- a/toxcore/forwarding_fuzz_test.cc +++ b/toxcore/forwarding_fuzz_test.cc @@ -46,7 +46,10 @@ void TestSendForwardRequest(Fuzz_Data &input) // rest of the fuzz data is input for malloc and network Fuzz_System sys(input); - Ptr logger(logger_new(), logger_kill); + Ptr logger(logger_new(sys.mem.get()), logger_kill); + if (logger == nullptr) { + return; + } Ptr net(new_networking_ex(logger.get(), sys.mem.get(), sys.ns.get(), &ipp.ip, ipp.port, ipp.port + 100, nullptr), @@ -72,7 +75,10 @@ void TestForwardReply(Fuzz_Data &input) // rest of the fuzz data is input for malloc and network Fuzz_System sys(input); - Ptr logger(logger_new(), logger_kill); + Ptr logger(logger_new(sys.mem.get()), logger_kill); + if (logger == nullptr) { + return; + } Ptr net(new_networking_ex(logger.get(), sys.mem.get(), sys.ns.get(), &ipp.ip, ipp.port, ipp.port + 100, nullptr), diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c index 33bfa40d34..9c44288511 100644 --- a/toxcore/friend_connection.c +++ b/toxcore/friend_connection.c @@ -875,6 +875,10 @@ void set_friend_request_callback(Friend_Connections *fr_c, fr_request_cb *fr_req int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, uint16_t length) { + // TODO(Jfreegman): This max packet size is too large to be handled by receiving clients + // when sent via the onion. We currently limit the length at a higher level, but + // this bounds check should be fixed to represent the max size of a packet that + // the onion client can handle. if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) { return -1; } @@ -1032,6 +1036,11 @@ void kill_friend_connections(Friend_Connections *fr_c) kill_friend_connection(fr_c, i); } + // there might be allocated NONE connections + if (fr_c->conns != nullptr) { + free(fr_c->conns); + } + lan_discovery_kill(fr_c->broadcast); free(fr_c); } diff --git a/toxcore/friend_requests.h b/toxcore/friend_requests.h index a78a570dfa..4f3ed0a8ab 100644 --- a/toxcore/friend_requests.h +++ b/toxcore/friend_requests.h @@ -14,7 +14,8 @@ #include "attributes.h" #include "friend_connection.h" -#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) +// TODO(Jfreegman): This should be the maximum size that an onion client can handle. +#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - 100) typedef struct Friend_Requests Friend_Requests; diff --git a/toxcore/group.c b/toxcore/group.c index 14e61e6ffc..7e27371061 100644 --- a/toxcore/group.c +++ b/toxcore/group.c @@ -9,7 +9,6 @@ #include "group.h" #include -#include #include #include "DHT.h" @@ -20,9 +19,11 @@ #include "friend_connection.h" #include "group_common.h" #include "logger.h" +#include "mem.h" #include "mono_time.h" #include "net_crypto.h" #include "network.h" +#include "sort.h" #include "state.h" #include "util.h" @@ -147,6 +148,7 @@ typedef struct Group_c { } Group_c; struct Group_Chats { + const Memory *mem; const Mono_Time *mono_time; Messenger *m; @@ -253,12 +255,12 @@ non_null() static bool realloc_conferences(Group_Chats *g_c, uint16_t num) { if (num == 0) { - free(g_c->chats); + mem_delete(g_c->mem, g_c->chats); g_c->chats = nullptr; return true; } - Group_c *newgroup_chats = (Group_c *)realloc(g_c->chats, num * sizeof(Group_c)); + Group_c *newgroup_chats = (Group_c *)mem_vrealloc(g_c->mem, g_c->chats, num, sizeof(Group_c)); if (newgroup_chats == nullptr) { return false; @@ -300,10 +302,10 @@ static int32_t create_group_chat(Group_Chats *g_c) } non_null() -static void wipe_group_c(Group_c *g) +static void wipe_group_c(const Memory *mem, Group_c *g) { - free(g->frozen); - free(g->group); + mem_delete(mem, g->frozen); + mem_delete(mem, g->group); crypto_memzero(g, sizeof(Group_c)); } @@ -318,7 +320,7 @@ static bool wipe_group_chat(Group_Chats *g_c, uint32_t groupnumber) return false; } - wipe_group_c(&g_c->chats[groupnumber]); + wipe_group_c(g_c->mem, &g_c->chats[groupnumber]); uint16_t i; @@ -667,7 +669,7 @@ static int get_frozen_index(const Group_c *g, uint16_t peer_number) } non_null() -static bool delete_frozen(Group_c *g, uint32_t frozen_index) +static bool delete_frozen(const Memory *mem, Group_c *g, uint32_t frozen_index) { if (frozen_index >= g->numfrozen) { return false; @@ -676,14 +678,14 @@ static bool delete_frozen(Group_c *g, uint32_t frozen_index) --g->numfrozen; if (g->numfrozen == 0) { - free(g->frozen); + mem_delete(mem, g->frozen); g->frozen = nullptr; } else { if (g->numfrozen != frozen_index) { g->frozen[frozen_index] = g->frozen[g->numfrozen]; } - Group_Peer *const frozen_temp = (Group_Peer *)realloc(g->frozen, g->numfrozen * sizeof(Group_Peer)); + Group_Peer *const frozen_temp = (Group_Peer *)mem_vrealloc(mem, g->frozen, g->numfrozen, sizeof(Group_Peer)); if (frozen_temp == nullptr) { return false; @@ -724,7 +726,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee /* Now thaw the peer */ - Group_Peer *temp = (Group_Peer *)realloc(g->group, (g->numpeers + 1) * sizeof(Group_Peer)); + Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->group, g->numpeers + 1, sizeof(Group_Peer)); if (temp == nullptr) { return -1; @@ -741,7 +743,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee ++g->numpeers; - delete_frozen(g, frozen_index); + delete_frozen(g_c->mem, g, frozen_index); if (g_c->peer_list_changed_callback != nullptr) { g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata); @@ -777,7 +779,7 @@ static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, cons const int frozen_index = frozen_in_group(g, real_pk); if (frozen_index >= 0) { - delete_frozen(g, frozen_index); + delete_frozen(g_c->mem, g, frozen_index); } } @@ -837,7 +839,7 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p delete_any_peer_with_pk(g_c, groupnumber, real_pk, userdata); - Group_Peer *temp = (Group_Peer *)realloc(g->group, (g->numpeers + 1) * sizeof(Group_Peer)); + Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->group, g->numpeers + 1, sizeof(Group_Peer)); if (temp == nullptr) { return -1; @@ -928,14 +930,14 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void void *peer_object = g->group[peer_index].object; if (g->numpeers == 0) { - free(g->group); + mem_delete(g_c->mem, g->group); g->group = nullptr; } else { if (g->numpeers != (uint32_t)peer_index) { g->group[peer_index] = g->group[g->numpeers]; } - Group_Peer *temp = (Group_Peer *)realloc(g->group, g->numpeers * sizeof(Group_Peer)); + Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->group, g->numpeers, sizeof(Group_Peer)); if (temp == nullptr) { return false; @@ -957,39 +959,90 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void /** Order peers with friends first and with more recently active earlier */ non_null() -static int cmp_frozen(const void *a, const void *b) +static bool group_peer_less_handler(const void *object, const void *a, const void *b) { const Group_Peer *pa = (const Group_Peer *)a; const Group_Peer *pb = (const Group_Peer *)b; - if (pa->is_friend ^ pb->is_friend) { - return pa->is_friend ? -1 : 1; + if (((pa->is_friend ? 1 : 0) ^ (pb->is_friend ? 1 : 0)) != 0) { + return pa->is_friend; } - return cmp_uint(pb->last_active, pa->last_active); + return cmp_uint(pb->last_active, pa->last_active) < 0; } +non_null() +static const void *group_peer_get_handler(const void *arr, uint32_t index) +{ + const Group_Peer *entries = (const Group_Peer *)arr; + return &entries[index]; +} + +non_null() +static void group_peer_set_handler(void *arr, uint32_t index, const void *val) +{ + Group_Peer *entries = (Group_Peer *)arr; + const Group_Peer *entry = (const Group_Peer *)val; + entries[index] = *entry; +} + +non_null() +static void *group_peer_subarr_handler(void *arr, uint32_t index, uint32_t size) +{ + Group_Peer *entries = (Group_Peer *)arr; + return &entries[index]; +} + +non_null() +static void *group_peer_alloc_handler(const void *object, uint32_t size) +{ + const Memory *mem = (const Memory *)object; + Group_Peer *tmp = (Group_Peer *)mem_valloc(mem, size, sizeof(Group_Peer)); + + if (tmp == nullptr) { + return nullptr; + } + + return tmp; +} + +non_null() +static void group_peer_delete_handler(const void *object, void *arr, uint32_t size) +{ + const Memory *mem = (const Memory *)object; + mem_delete(mem, arr); +} + +static const Sort_Funcs group_peer_cmp_funcs = { + group_peer_less_handler, + group_peer_get_handler, + group_peer_set_handler, + group_peer_subarr_handler, + group_peer_alloc_handler, + group_peer_delete_handler, +}; + /** @brief Delete frozen peers as necessary to ensure at most `g->maxfrozen` remain. * * @retval true if any frozen peers are removed. */ non_null() -static bool delete_old_frozen(Group_c *g) +static bool delete_old_frozen(Group_c *g, const Memory *mem) { if (g->numfrozen <= g->maxfrozen) { return false; } if (g->maxfrozen == 0) { - free(g->frozen); + mem_delete(mem, g->frozen); g->frozen = nullptr; g->numfrozen = 0; return true; } - qsort(g->frozen, g->numfrozen, sizeof(Group_Peer), cmp_frozen); + merge_sort(g->frozen, g->numfrozen, mem, &group_peer_cmp_funcs); - Group_Peer *temp = (Group_Peer *)realloc(g->frozen, g->maxfrozen * sizeof(Group_Peer)); + Group_Peer *temp = (Group_Peer *)mem_vrealloc(mem, g->frozen, g->maxfrozen, sizeof(Group_Peer)); if (temp == nullptr) { return false; @@ -1014,7 +1067,7 @@ static bool freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, return false; } - Group_Peer *temp = (Group_Peer *)realloc(g->frozen, (g->numfrozen + 1) * sizeof(Group_Peer)); + Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->m->mem, g->frozen, g->numfrozen + 1, sizeof(Group_Peer)); if (temp == nullptr) { return false; @@ -1032,7 +1085,7 @@ static bool freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, ++g->numfrozen; - delete_old_frozen(g); + delete_old_frozen(g, g_c->m->mem); return true; } @@ -1519,7 +1572,7 @@ int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t } g->maxfrozen = maxfrozen; - delete_old_frozen(g); + delete_old_frozen(g, g_c->m->mem); return 0; } @@ -2520,7 +2573,7 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8 non_null(1, 3) nullable(6) static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length, - int connection_index, void *userdata) + uint32_t connection_index, void *userdata) { if (length == 0) { return; @@ -2832,7 +2885,7 @@ static bool check_message_info(uint32_t message_number, uint8_t message_id, Grou non_null(1, 3) nullable(6) static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length, - int connection_index, void *userdata) + uint32_t connection_index, void *userdata) { if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) { return; @@ -3612,7 +3665,7 @@ static uint32_t load_group(Group_c *g, const Group_Chats *g_c, const uint8_t *da } // This is inefficient, but allows us to check data consistency before allocating memory - Group_Peer *tmp_frozen = (Group_Peer *)realloc(g->frozen, (j + 1) * sizeof(Group_Peer)); + Group_Peer *tmp_frozen = (Group_Peer *)mem_vrealloc(g_c->mem, g->frozen, j + 1, sizeof(Group_Peer)); if (tmp_frozen == nullptr) { // Memory allocation failure @@ -3758,12 +3811,13 @@ Group_Chats *new_groupchats(const Mono_Time *mono_time, Messenger *m) return nullptr; } - Group_Chats *temp = (Group_Chats *)calloc(1, sizeof(Group_Chats)); + Group_Chats *temp = (Group_Chats *)mem_alloc(m->mem, sizeof(Group_Chats)); if (temp == nullptr) { return nullptr; } + temp->mem = m->mem; temp->mono_time = mono_time; temp->m = m; temp->fr_c = m->fr_c; @@ -3814,7 +3868,7 @@ void kill_groupchats(Group_Chats *g_c) m_callback_conference_invite(g_c->m, nullptr); set_global_status_callback(g_c->m->fr_c, nullptr, nullptr); g_c->m->conferences_object = nullptr; - free(g_c); + mem_delete(g_c->mem, g_c); } /** diff --git a/toxcore/group_announce_fuzz_test.cc b/toxcore/group_announce_fuzz_test.cc index eb0dfb6290..9f5655ac15 100644 --- a/toxcore/group_announce_fuzz_test.cc +++ b/toxcore/group_announce_fuzz_test.cc @@ -19,7 +19,8 @@ void TestUnpackAnnouncesList(Fuzz_Data &input) // TODO(iphydf): How do we know the packed size? CONSUME1_OR_RETURN(const uint16_t, packed_size, input); - Logger *logger = logger_new(); + Test_Memory mem; + Logger *logger = logger_new(mem); if (gca_unpack_announces_list(logger, input.data(), input.size(), announces.data(), max_count) != -1) { // Always allocate at least something to avoid passing nullptr to functions below. @@ -38,7 +39,8 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input) // TODO(iphydf): How do we know the packed size? CONSUME1_OR_RETURN(const uint16_t, packed_size, input); - Logger *logger = logger_new(); + Test_Memory mem; + Logger *logger = logger_new(mem); if (gca_unpack_public_announce(logger, input.data(), input.size(), &public_announce) != -1) { // Always allocate at least something to avoid passing nullptr to functions below. std::vector packed(packed_size + 1); @@ -50,7 +52,7 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input) void TestDoGca(Fuzz_Data &input) { Test_Memory mem; - std::unique_ptr logger(logger_new(), logger_kill); + std::unique_ptr logger(logger_new(mem), logger_kill); uint64_t clock = 1; std::unique_ptr> mono_time( diff --git a/toxcore/group_announce_test.cc b/toxcore/group_announce_test.cc index 2918dc76c6..f1027f3437 100644 --- a/toxcore/group_announce_test.cc +++ b/toxcore/group_announce_test.cc @@ -118,11 +118,12 @@ TEST_F(Announces, AnnouncesGetAndCleanup) struct AnnouncesPack : ::testing::Test { protected: std::vector announces_; + Test_Memory mem_; Logger *logger_ = nullptr; void SetUp() override { - logger_ = logger_new(); + logger_ = logger_new(mem_); ASSERT_NE(logger_, nullptr); // Add an announce without TCP relay. diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 03077d0806..31962d530e 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c @@ -30,6 +30,7 @@ #include "group_moderation.h" #include "group_pack.h" #include "logger.h" +#include "mem.h" #include "mono_time.h" #include "net_crypto.h" #include "network.h" @@ -1473,8 +1474,8 @@ static bool sign_gc_shared_state(GC_Chat *chat) * Return -2 on decryption failure. * Return -3 if plaintext payload length is invalid. */ -non_null(1, 2, 3, 5, 6) nullable(4) -static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id, +non_null(1, 2, 3, 4, 6, 7) nullable(5) +static int group_packet_unwrap(const Logger *log, const Memory *mem, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id, uint8_t *packet_type, const uint8_t *packet, uint16_t length) { assert(data != nullptr); @@ -1492,7 +1493,7 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui return -1; } - int plain_len = decrypt_data_symmetric(gconn->session_shared_key, packet, packet + CRYPTO_NONCE_SIZE, + int plain_len = decrypt_data_symmetric(mem, gconn->session_shared_key, packet, packet + CRYPTO_NONCE_SIZE, length - CRYPTO_NONCE_SIZE, plain); if (plain_len <= 0) { @@ -1533,7 +1534,7 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui } int group_packet_wrap( - const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet, + const Logger *log, const Memory *mem, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet, uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id, uint8_t gp_packet_type, Net_Packet_Type net_packet_type) { @@ -1588,7 +1589,7 @@ int group_packet_wrap( return -2; } - const int enc_len = encrypt_data_symmetric(shared_key, nonce, plain, plain_len, encrypt); + const int enc_len = encrypt_data_symmetric(mem, shared_key, nonce, plain, plain_len, encrypt); free(plain); @@ -1634,7 +1635,7 @@ static bool send_lossy_group_packet(const GC_Chat *chat, const GC_Connection *gc } const int len = group_packet_wrap( - chat->log, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet, + chat->log, chat->mem, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet, packet_size, data, length, 0, packet_type, NET_PACKET_GC_LOSSY); if (len < 0) { @@ -5508,7 +5509,7 @@ static int handle_gc_broadcast(const GC_Session *c, GC_Chat *chat, uint32_t peer * Return -2 if decryption fails. */ non_null() -static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_sk, const uint8_t *sender_pk, +static int unwrap_group_handshake_packet(const Logger *log, const Memory *mem, const uint8_t *self_sk, const uint8_t *sender_pk, uint8_t *plain, size_t plain_size, const uint8_t *packet, uint16_t length) { if (length <= CRYPTO_NONCE_SIZE) { @@ -5516,7 +5517,7 @@ static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_ return -1; } - const int plain_len = decrypt_data(sender_pk, self_sk, packet, packet + CRYPTO_NONCE_SIZE, + const int plain_len = decrypt_data(mem, sender_pk, self_sk, packet, packet + CRYPTO_NONCE_SIZE, length - CRYPTO_NONCE_SIZE, plain); if (plain_len < 0 || (uint32_t)plain_len != plain_size) { @@ -5539,7 +5540,7 @@ static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_ */ non_null() static int wrap_group_handshake_packet( - const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *self_sk, + const Logger *log, const Memory *mem, const Random *rng, const uint8_t *self_pk, const uint8_t *self_sk, const uint8_t *target_pk, uint8_t *packet, uint32_t packet_size, const uint8_t *data, uint16_t length) { @@ -5558,7 +5559,7 @@ static int wrap_group_handshake_packet( return -2; } - const int enc_len = encrypt_data(target_pk, self_sk, nonce, data, length, encrypt); + const int enc_len = encrypt_data(mem, target_pk, self_sk, nonce, data, length, encrypt); if (enc_len < 0 || (size_t)enc_len != encrypt_buf_size) { LOGGER_ERROR(log, "Failed to encrypt group handshake packet (len: %d)", enc_len); @@ -5622,7 +5623,7 @@ static int make_gc_handshake_packet(const GC_Chat *chat, const GC_Connection *gc } const int enc_len = wrap_group_handshake_packet( - chat->log, chat->rng, chat->self_public_key.enc, chat->self_secret_key.enc, + chat->log, chat->mem, chat->rng, chat->self_public_key.enc, chat->self_secret_key.enc, gconn->addr.public_key.enc, packet, (uint16_t)packet_size, data, length); if (enc_len != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + nodes_size) { @@ -5951,7 +5952,7 @@ static int handle_gc_handshake_packet(GC_Chat *chat, const uint8_t *sender_pk, c return -1; } - const int plain_len = unwrap_group_handshake_packet(chat->log, chat->self_secret_key.enc, sender_pk, data, + const int plain_len = unwrap_group_handshake_packet(chat->log, chat->mem, chat->self_secret_key.enc, sender_pk, data, data_buf_size, packet, length); if (plain_len < GC_MIN_HS_PACKET_PAYLOAD_SIZE) { @@ -6181,7 +6182,7 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const uint8_t packet_type; uint64_t message_id; - const int len = group_packet_unwrap(chat->log, gconn, data, &message_id, &packet_type, packet, length); + const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, &message_id, &packet_type, packet, length); if (len < 0) { Ip_Ntoa ip_str; @@ -6334,7 +6335,7 @@ static bool handle_gc_lossy_packet(const GC_Session *c, GC_Chat *chat, const uin uint8_t packet_type; - const int len = group_packet_unwrap(chat->log, gconn, data, nullptr, &packet_type, packet, length); + const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, nullptr, &packet_type, packet, length); if (len <= 0) { Ip_Ntoa ip_str; @@ -7732,10 +7733,52 @@ int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state, return group_number; } +int gc_rejoin_group(GC_Session *c, GC_Chat *chat, const uint8_t *passwd, uint16_t passwd_len) +{ + if (c == nullptr) { + LOGGER_ERROR(chat->log, "NULL group session pointer."); + return -1; + } + + if (passwd != nullptr && passwd_len > 0) { + if (!set_gc_password_local(chat, passwd, passwd_len)) { + LOGGER_WARNING(chat->log, "Failed to set new password during reconnect."); + } + } + + chat->time_connected = 0; + + if (group_can_handle_packets(chat)) { + send_gc_self_exit(chat, nullptr, 0); + } + + for (uint32_t i = 1; i < chat->numpeers; ++i) { + GC_Connection *gconn = get_gc_connection(chat, i); + assert(gconn != nullptr); + + gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0); + } + + if (is_public_chat(chat)) { + kill_group_friend_connection(c, chat); + + if (!m_create_group_connection(c->messenger, chat)) { + LOGGER_WARNING(chat->log, "Failed to create new messenger connection for group"); + return -1; + } + + chat->update_self_announces = true; + } + + chat->connection_state = CS_CONNECTING; + + return 0; +} + int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, size_t nick_length, const uint8_t *passwd, uint16_t passwd_len) { - if (chat_id == nullptr || group_exists(c, chat_id) || getfriend_id(c->messenger, chat_id) != -1) { + if (chat_id == nullptr) { return -2; } @@ -7747,6 +7790,18 @@ int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, si return -4; } + GC_Chat *existing_group = gc_get_group_by_public_key(c, chat_id); + + // If we're already in the group we try to reconnect to it + if (existing_group != nullptr) { + const int ret = gc_rejoin_group(c, existing_group, passwd, passwd_len); + return ret != 0 ? -6 : ret; + } + + if (getfriend_id(c->messenger, chat_id) != -1) { + return -2; + } + const int group_number = create_new_group(c, nick, nick_length, false, GI_PUBLIC); if (group_number == -1) { @@ -7805,41 +7860,6 @@ bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat) return true; } -int gc_rejoin_group(GC_Session *c, GC_Chat *chat) -{ - if (c == nullptr || chat == nullptr) { - return -1; - } - - chat->time_connected = 0; - - if (group_can_handle_packets(chat)) { - send_gc_self_exit(chat, nullptr, 0); - } - - for (uint32_t i = 1; i < chat->numpeers; ++i) { - GC_Connection *gconn = get_gc_connection(chat, i); - assert(gconn != nullptr); - - gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_SELF_DISCONNECTED, nullptr, 0); - } - - if (is_public_chat(chat)) { - kill_group_friend_connection(c, chat); - - if (!m_create_group_connection(c->messenger, chat)) { - LOGGER_WARNING(chat->log, "Failed to create new messenger connection for group"); - return -2; - } - - chat->update_self_announces = true; - } - - chat->connection_state = CS_CONNECTING; - - return 0; -} - bool group_not_added(const GC_Session *c, const uint8_t *chat_id, uint32_t length) { if (length < CHAT_ID_SIZE) { @@ -8353,7 +8373,7 @@ bool gc_group_is_valid(const GC_Chat *chat) /** Return true if `group_number` designates an active group in session `c`. */ static bool group_number_valid(const GC_Session *c, int group_number) { - if (group_number < 0 || group_number >= c->chats_index) { + if (group_number < 0 || (uint32_t)group_number >= c->chats_index) { return false; } @@ -8408,19 +8428,7 @@ GC_Chat *gc_get_group_by_public_key(const GC_Session *c, const uint8_t *public_k /** Return True if chat_id exists in the session chat array */ static bool group_exists(const GC_Session *c, const uint8_t *chat_id) { - for (uint32_t i = 0; i < c->chats_index; ++i) { - const GC_Chat *chat = &c->chats[i]; - - if (chat->connection_state == CS_NONE) { - continue; - } - - if (memcmp(get_chat_id(&chat->chat_public_key), chat_id, CHAT_ID_SIZE) == 0) { - return true; - } - } - - return false; + return gc_get_group_by_public_key(c, chat_id) != nullptr; } /** Creates a new 32-byte session encryption keypair and puts the results in `public_key` and `secret_key`. */ diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h index d22ce400e6..aa92a9ce26 100644 --- a/toxcore/group_chats.h +++ b/toxcore/group_chats.h @@ -22,6 +22,7 @@ #include "group_common.h" #include "group_connection.h" #include "logger.h" +#include "mem.h" #include "network.h" #define GC_PING_TIMEOUT 12 @@ -141,9 +142,9 @@ int get_peer_number_of_enc_pk(const GC_Chat *chat, const uint8_t *public_enc_key * Return -2 if malloc fails. * Return -3 if encryption fails. */ -non_null(1, 2, 3, 4, 5) nullable(7) +non_null(1, 2, 3, 4, 5, 6) nullable(8) int group_packet_wrap( - const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet, + const Logger *log, const Memory *mem, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet, uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id, uint8_t gp_packet_type, Net_Packet_Type net_packet_type); @@ -675,8 +676,8 @@ bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat); * Returns -1 if the group handler object or chat object is null. * Returns -2 if the Messenger friend connection fails to initialize. */ -non_null() -int gc_rejoin_group(GC_Session *c, GC_Chat *chat); +non_null(1, 2) nullable(3) +int gc_rejoin_group(GC_Session *c, GC_Chat *chat, const uint8_t *passwd, uint16_t passwd_len); /** @brief Joins a group using the invite data received in a friend's group invite. * diff --git a/toxcore/group_common.h b/toxcore/group_common.h index daa8fe17c8..0e965bb148 100644 --- a/toxcore/group_common.h +++ b/toxcore/group_common.h @@ -52,7 +52,7 @@ #define MAX_GC_PACKET_SIZE (MAX_GC_PACKET_CHUNK_SIZE * 100) /* Max number of messages to store in the send/recv arrays */ -#define GCC_BUFFER_SIZE 8192 +#define GCC_BUFFER_SIZE 2048 /** Self UDP status. Must correspond to return values from `ipport_self_copy()`. */ typedef enum Self_UDP_Status { diff --git a/toxcore/group_connection.c b/toxcore/group_connection.c index 1c2d1ec3da..6a2fedbedc 100644 --- a/toxcore/group_connection.c +++ b/toxcore/group_connection.c @@ -629,7 +629,7 @@ int gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connectio } const int enc_len = group_packet_wrap( - chat->log, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet, + chat->log, chat->mem, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet, packet_size, data, length, message_id, packet_type, NET_PACKET_GC_LOSSLESS); if (enc_len < 0) { diff --git a/toxcore/group_moderation_test.cc b/toxcore/group_moderation_test.cc index ea72023e93..89555b9a1e 100644 --- a/toxcore/group_moderation_test.cc +++ b/toxcore/group_moderation_test.cc @@ -191,9 +191,9 @@ struct SanctionsListMod : ::testing::Test { protected: Extended_Public_Key pk; Extended_Secret_Key sk; - Logger *log = logger_new(); Test_Random rng; Test_Memory mem; + Logger *log = logger_new(mem); Moderation mod{mem}; Mod_Sanction sanctions[2] = {}; diff --git a/toxcore/group_onion_announce.c b/toxcore/group_onion_announce.c index d05db09a07..6d680137b4 100644 --- a/toxcore/group_onion_announce.c +++ b/toxcore/group_onion_announce.c @@ -14,6 +14,7 @@ #include "crypto_core.h" #include "group_announce.h" #include "logger.h" +#include "mem.h" #include "mono_time.h" #include "network.h" #include "onion_announce.h" @@ -76,7 +77,7 @@ void gca_onion_init(GC_Announces_List *group_announce, Onion_Announce *onion_a) } int create_gca_announce_request( - const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data, const uint8_t *gc_data, uint16_t gc_data_length) @@ -108,7 +109,7 @@ int create_gca_announce_request( random_nonce(rng, packet + 1); memcpy(packet + 1 + CRYPTO_NONCE_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE); - const int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, + const int len = encrypt_data(mem, dest_client_id, secret_key, packet + 1, plain, encrypted_size, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); const uint32_t full_length = (uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE; diff --git a/toxcore/group_onion_announce.h b/toxcore/group_onion_announce.h index 5fbac02e0a..bc9edb109a 100644 --- a/toxcore/group_onion_announce.h +++ b/toxcore/group_onion_announce.h @@ -9,6 +9,7 @@ #include "attributes.h" #include "crypto_core.h" #include "group_announce.h" +#include "mem.h" #include "onion_announce.h" non_null() @@ -16,7 +17,7 @@ void gca_onion_init(GC_Announces_List *group_announce, Onion_Announce *onion_a); non_null() int create_gca_announce_request( - const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data, const uint8_t *gc_data, uint16_t gc_data_length); diff --git a/toxcore/group_pack.c b/toxcore/group_pack.c index e3af82c67a..c20d6a1213 100644 --- a/toxcore/group_pack.c +++ b/toxcore/group_pack.c @@ -26,46 +26,46 @@ #include "network.h" #include "util.h" -bool group_privacy_state_from_int(uint8_t value, Group_Privacy_State *out) +bool group_privacy_state_from_int(uint8_t value, Group_Privacy_State *out_enum) { switch (value) { case GI_PUBLIC: { - *out = GI_PUBLIC; + *out_enum = GI_PUBLIC; return true; } case GI_PRIVATE: { - *out = GI_PRIVATE; + *out_enum = GI_PRIVATE; return true; } default: { - *out = GI_PUBLIC; + *out_enum = GI_PUBLIC; return false; } } } -bool group_voice_state_from_int(uint8_t value, Group_Voice_State *out) +bool group_voice_state_from_int(uint8_t value, Group_Voice_State *out_enum) { switch (value) { case GV_ALL: { - *out = GV_ALL; + *out_enum = GV_ALL; return true; } case GV_MODS: { - *out = GV_MODS; + *out_enum = GV_MODS; return true; } case GV_FOUNDER: { - *out = GV_FOUNDER; + *out_enum = GV_FOUNDER; return true; } default: { - *out = GV_ALL; + *out_enum = GV_ALL; return false; } } diff --git a/toxcore/group_pack.h b/toxcore/group_pack.h index 03252fb86d..4c999132db 100644 --- a/toxcore/group_pack.h +++ b/toxcore/group_pack.h @@ -34,8 +34,8 @@ non_null() bool gc_load_unpack_group(GC_Chat *chat, Bin_Unpack *bu); non_null() -bool group_privacy_state_from_int(uint8_t value, Group_Privacy_State *out); +bool group_privacy_state_from_int(uint8_t value, Group_Privacy_State *out_enum); non_null() -bool group_voice_state_from_int(uint8_t value, Group_Voice_State *out); +bool group_voice_state_from_int(uint8_t value, Group_Voice_State *out_enum); #endif /* C_TOXCORE_TOXCORE_GROUP_PACK_H */ diff --git a/toxcore/logger.c b/toxcore/logger.c index 67fa52330b..69d7f50fc3 100644 --- a/toxcore/logger.c +++ b/toxcore/logger.c @@ -13,69 +13,41 @@ #include #include -#include "attributes.h" #include "ccompat.h" +#include "mem.h" struct Logger { + const Memory *mem; + logger_cb *callback; void *context; void *userdata; }; -#ifndef NDEBUG -static const char *logger_level_name(Logger_Level level) -{ - switch (level) { - case LOGGER_LEVEL_TRACE: - return "TRACE"; - - case LOGGER_LEVEL_DEBUG: - return "DEBUG"; - - case LOGGER_LEVEL_INFO: - return "INFO"; - - case LOGGER_LEVEL_WARNING: - return "WARNING"; - - case LOGGER_LEVEL_ERROR: - return "ERROR"; - } - - return ""; -} -#endif /* NDEBUG */ - -non_null(1, 3, 5, 6) nullable(7) -static void logger_stderr_handler(void *context, Logger_Level level, const char *file, int line, const char *func, - const char *message, void *userdata) -{ -#ifndef NDEBUG - // GL stands for "global logger". - fprintf(stderr, "[GL] %s %s:%d(%s): %s\n", logger_level_name(level), file, line, func, message); - fprintf(stderr, "Default stderr logger triggered; aborting program\n"); - abort(); -#endif /* NDEBUG */ -} - -static const Logger logger_stderr = { - logger_stderr_handler, - nullptr, - nullptr, -}; - /* * Public Functions */ -Logger *logger_new(void) +Logger *logger_new(const Memory *mem) { - return (Logger *)calloc(1, sizeof(Logger)); + Logger *log = (Logger *)mem_alloc(mem, sizeof(Logger)); + + if (log == nullptr) { + return nullptr; + } + + log->mem = mem; + + return log; } void logger_kill(Logger *log) { - free(log); + if (log == nullptr) { + return; + } + + mem_delete(log->mem, log); } void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata) @@ -89,7 +61,7 @@ void logger_write(const Logger *log, Logger_Level level, const char *file, int l const char *format, ...) { if (log == nullptr) { - log = &logger_stderr; + return; } if (log->callback == nullptr) { diff --git a/toxcore/logger.h b/toxcore/logger.h index 830db883aa..1c7c0077e2 100644 --- a/toxcore/logger.h +++ b/toxcore/logger.h @@ -12,6 +12,7 @@ #include #include "attributes.h" +#include "mem.h" #ifdef __cplusplus extern "C" { @@ -38,7 +39,8 @@ typedef void logger_cb(void *context, Logger_Level level, const char *file, int /** * Creates a new logger with logging disabled (callback is NULL) by default. */ -Logger *logger_new(void); +non_null() +Logger *logger_new(const Memory *mem); /** * Frees all resources associated with the logger. diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 1680b078b7..c17ff6c2ed 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -122,9 +122,6 @@ typedef struct Crypto_Connection { bool maximum_speed_reached; - /* Must be a pointer, because the struct is moved in memory */ - pthread_mutex_t *mutex; - dht_pk_cb *dht_pk_callback; void *dht_pk_callback_object; uint32_t dht_pk_callback_number; @@ -143,10 +140,6 @@ struct Net_Crypto { TCP_Connections *tcp_c; Crypto_Connection *crypto_connections; - pthread_mutex_t tcp_mutex; - - pthread_mutex_t connections_mutex; - unsigned int connection_use_counter; uint32_t crypto_connections_length; /* Length of connections array. */ @@ -237,7 +230,7 @@ static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, const uin packet[0] = NET_PACKET_COOKIE_REQUEST; memcpy(packet + 1, dht_get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE); memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); - const int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain), + const int len = encrypt_data_symmetric(c->mem, shared_key, nonce, plain, sizeof(plain), packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); if (len != COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) { @@ -253,7 +246,7 @@ static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, const uin * @retval 0 on success. */ non_null() -static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t *cookie, const uint8_t *bytes, +static int create_cookie(const Memory *mem, const Random *rng, const Mono_Time *mono_time, uint8_t *cookie, const uint8_t *bytes, const uint8_t *encryption_key) { uint8_t contents[COOKIE_CONTENTS_LENGTH]; @@ -261,7 +254,7 @@ static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t memcpy(contents, &temp_time, sizeof(temp_time)); memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH); random_nonce(rng, cookie); - const int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE); + const int len = encrypt_data_symmetric(mem, encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE); if (len != COOKIE_LENGTH - CRYPTO_NONCE_SIZE) { return -1; @@ -276,11 +269,11 @@ static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t * @retval 0 on success. */ non_null() -static int open_cookie(const Mono_Time *mono_time, uint8_t *bytes, const uint8_t *cookie, +static int open_cookie(const Memory *mem, const Mono_Time *mono_time, uint8_t *bytes, const uint8_t *cookie, const uint8_t *encryption_key) { uint8_t contents[COOKIE_CONTENTS_LENGTH]; - const int len = decrypt_data_symmetric(encryption_key, cookie, cookie + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(mem, encryption_key, cookie, cookie + CRYPTO_NONCE_SIZE, COOKIE_LENGTH - CRYPTO_NONCE_SIZE, contents); if (len != sizeof(contents)) { @@ -315,14 +308,14 @@ static int create_cookie_response(const Net_Crypto *c, uint8_t *packet, const ui memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; - if (create_cookie(c->rng, c->mono_time, plain, cookie_plain, c->secret_symmetric_key) != 0) { + if (create_cookie(c->mem, c->rng, c->mono_time, plain, cookie_plain, c->secret_symmetric_key) != 0) { return -1; } memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t)); packet[0] = NET_PACKET_COOKIE_RESPONSE; random_nonce(c->rng, packet + 1); - const int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE); + const int len = encrypt_data_symmetric(c->mem, shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE); if (len != COOKIE_RESPONSE_LENGTH - (1 + CRYPTO_NONCE_SIZE)) { return -1; @@ -349,7 +342,7 @@ static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, ui memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE); const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key); memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE); - const int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + const int len = decrypt_data_symmetric(c->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE, request_plain); @@ -446,7 +439,7 @@ static int tcp_oob_handle_cookie_request(const Net_Crypto *c, unsigned int tcp_c * @retval COOKIE_LENGTH on success. */ non_null() -static int handle_cookie_response(uint8_t *cookie, uint64_t *number, +static int handle_cookie_response(const Memory *mem, uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint16_t length, const uint8_t *shared_key) { @@ -455,7 +448,7 @@ static int handle_cookie_response(uint8_t *cookie, uint64_t *number, } uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; - const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(mem, shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, length - (1 + CRYPTO_NONCE_SIZE), plain); if (len != sizeof(plain)) { @@ -488,13 +481,13 @@ static int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const u memcpy(cookie_plain, peer_real_pk, CRYPTO_PUBLIC_KEY_SIZE); memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, peer_dht_pubkey, CRYPTO_PUBLIC_KEY_SIZE); - if (create_cookie(c->rng, c->mono_time, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, + if (create_cookie(c->mem, c->rng, c->mono_time, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, cookie_plain, c->secret_symmetric_key) != 0) { return -1; } random_nonce(c->rng, packet + 1 + COOKIE_LENGTH); - const int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), + const int len = encrypt_data(c->mem, peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE); if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE)) { @@ -535,7 +528,7 @@ static bool handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t uint8_t cookie_plain[COOKIE_DATA_LENGTH]; - if (open_cookie(c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) { + if (open_cookie(c->mem, c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) { return false; } @@ -547,7 +540,7 @@ static bool handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t crypto_sha512(cookie_hash, packet + 1, COOKIE_LENGTH); uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH]; - const int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + const int len = decrypt_data(c->mem, cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE, HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain); @@ -691,7 +684,6 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t bool direct_send_attempt = false; - pthread_mutex_lock(conn->mutex); const IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id); // TODO(irungentoo): on bad networks, direct connections might not last indefinitely. @@ -703,11 +695,9 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t if (direct_connected) { if ((uint32_t)sendpacket(dht_get_net(c->dht), &ip_port, data, length) == length) { - pthread_mutex_unlock(conn->mutex); return 0; } - pthread_mutex_unlock(conn->mutex); LOGGER_WARNING(c->log, "sending packet of length %d failed", length); return -1; } @@ -724,19 +714,12 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t } } - pthread_mutex_unlock(conn->mutex); - pthread_mutex_lock(&c->tcp_mutex); const int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); - pthread_mutex_unlock(&c->tcp_mutex); - - pthread_mutex_lock(conn->mutex); if (ret == 0) { conn->last_tcp_sent = current_time_monotonic(c->mono_time); } - pthread_mutex_unlock(conn->mutex); - if (direct_send_attempt) { return 0; } @@ -1097,21 +1080,18 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_ return -1; } - pthread_mutex_lock(conn->mutex); const uint16_t packet_size = 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE; VLA(uint8_t, packet, packet_size); packet[0] = NET_PACKET_CRYPTO_DATA; memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); - const int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); + const int len = encrypt_data_symmetric(c->mem, conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); if (len + 1 + sizeof(uint16_t) != packet_size) { LOGGER_ERROR(c->log, "encryption failed: %d", len); - pthread_mutex_unlock(conn->mutex); return -1; } increment_nonce(conn->sent_nonce); - pthread_mutex_unlock(conn->mutex); return send_packet_to(c, crypt_connection_id, packet, packet_size); } @@ -1207,9 +1187,7 @@ static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, cons dt.sent_time = 0; dt.length = length; memcpy(dt.data, data, length); - pthread_mutex_lock(conn->mutex); const int64_t packet_num = add_data_end_of_buffer(c->log, c->mem, &conn->send_array, &dt); - pthread_mutex_unlock(conn->mutex); if (packet_num == -1) { return -1; @@ -1277,7 +1255,7 @@ static int handle_data_packet(const Net_Crypto *c, int crypt_connection_id, uint net_unpack_u16(packet + 1, &num); const uint16_t diff = num - num_cur_nonce; increment_nonce_number(nonce, diff); - const int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t), + const int len = decrypt_data_symmetric(c->mem, conn->shared_key, nonce, packet + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), data); if ((unsigned int)len != length - crypto_packet_overhead) { @@ -1521,18 +1499,7 @@ static void connection_kill(Net_Crypto *c, int crypt_connection_id, void *userda false, userdata); } - while (true) { /* TODO(irungentoo): is this really the best way to do this? */ - pthread_mutex_lock(&c->connections_mutex); - - if (c->connection_use_counter == 0) { - break; - } - - pthread_mutex_unlock(&c->connections_mutex); - } - crypto_kill(c, crypt_connection_id); - pthread_mutex_unlock(&c->connections_mutex); } /** @brief Handle a received data packet. @@ -1635,9 +1602,7 @@ static int handle_data_packet_core(Net_Crypto *c, int crypt_connection_id, const } while (true) { - pthread_mutex_lock(conn->mutex); const int ret = read_data_beg_buffer(c->mem, &conn->recv_array, &dt); - pthread_mutex_unlock(conn->mutex); if (ret == -1) { break; @@ -1697,7 +1662,7 @@ static int handle_packet_cookie_response(Net_Crypto *c, int crypt_connection_id, uint8_t cookie[COOKIE_LENGTH]; uint64_t number; - if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) { + if (handle_cookie_response(c->mem, cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) { return -1; } @@ -1835,16 +1800,6 @@ static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) non_null() static int create_crypto_connection(Net_Crypto *c) { - while (true) { /* TODO(irungentoo): is this really the best way to do this? */ - pthread_mutex_lock(&c->connections_mutex); - - if (c->connection_use_counter == 0) { - break; - } - - pthread_mutex_unlock(&c->connections_mutex); - } - int id = -1; for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { @@ -1863,30 +1818,17 @@ static int create_crypto_connection(Net_Crypto *c) } if (id != -1) { - pthread_mutex_t *mutex = (pthread_mutex_t *)mem_alloc(c->mem, sizeof(pthread_mutex_t)); - - if (mutex == nullptr) { - pthread_mutex_unlock(&c->connections_mutex); - return -1; - } - - if (pthread_mutex_init(mutex, nullptr) != 0) { - mem_delete(c->mem, mutex); - pthread_mutex_unlock(&c->connections_mutex); - return -1; - } - // Memsetting float/double to 0 is non-portable, so we explicitly set them to 0 c->crypto_connections[id].packet_recv_rate = 0.0; c->crypto_connections[id].packet_send_rate = 0.0; c->crypto_connections[id].last_packets_left_rem = 0.0; c->crypto_connections[id].packet_send_rate_requested = 0.0; c->crypto_connections[id].last_packets_left_requested_rem = 0.0; - c->crypto_connections[id].mutex = mutex; + + // TODO(Green-Sky): This enum is likely unneeded and the same as FREE. c->crypto_connections[id].status = CRYPTO_CONN_NO_CONNECTION; } - pthread_mutex_unlock(&c->connections_mutex); return id; } @@ -1914,8 +1856,6 @@ static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) uint32_t i; - pthread_mutex_destroy(c->crypto_connections[crypt_connection_id].mutex); - mem_delete(c->mem, c->crypto_connections[crypt_connection_id].mutex); crypto_memzero(&c->crypto_connections[crypt_connection_id], sizeof(Crypto_Connection)); /* check if we can resize the connections array */ @@ -2098,9 +2038,7 @@ int accept_crypto_connection(Net_Crypto *c, const New_Connection *n_c) return -1; } - pthread_mutex_lock(&c->tcp_mutex); const int connection_number_tcp = new_tcp_connection_to(c->tcp_c, n_c->dht_public_key, crypt_connection_id); - pthread_mutex_unlock(&c->tcp_mutex); if (connection_number_tcp == -1) { wipe_crypto_connection(c, crypt_connection_id); @@ -2117,9 +2055,7 @@ int accept_crypto_connection(Net_Crypto *c, const New_Connection *n_c) conn->status = CRYPTO_CONN_NOT_CONFIRMED; if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) { - pthread_mutex_lock(&c->tcp_mutex); kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); - pthread_mutex_unlock(&c->tcp_mutex); wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -2155,9 +2091,7 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const u Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; - pthread_mutex_lock(&c->tcp_mutex); const int connection_number_tcp = new_tcp_connection_to(c->tcp_c, dht_public_key, crypt_connection_id); - pthread_mutex_unlock(&c->tcp_mutex); if (connection_number_tcp == -1) { wipe_crypto_connection(c, crypt_connection_id); @@ -2181,9 +2115,7 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const u if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number, conn->shared_key) != sizeof(cookie_request) || new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) { - pthread_mutex_lock(&c->tcp_mutex); kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); - pthread_mutex_unlock(&c->tcp_mutex); wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -2241,11 +2173,7 @@ static int tcp_data_callback(void *object, int crypt_connection_id, const uint8_ return tcp_handle_cookie_request(c, conn->connection_number_tcp, packet, length); } - // This unlocks the mutex that at this point is locked by do_tcp before - // calling do_tcp_connections. - pthread_mutex_unlock(&c->tcp_mutex); const int ret = handle_packet_connection(c, crypt_connection_id, packet, length, false, userdata); - pthread_mutex_lock(&c->tcp_mutex); if (ret != 0) { return -1; @@ -2295,10 +2223,7 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, const IP_Port *ip return -1; } - pthread_mutex_lock(&c->tcp_mutex); - const int ret = add_tcp_relay_connection(c->tcp_c, conn->connection_number_tcp, ip_port, public_key); - pthread_mutex_unlock(&c->tcp_mutex); - return ret; + return add_tcp_relay_connection(c->tcp_c, conn->connection_number_tcp, ip_port, public_key); } /** @brief Add a tcp relay to the array. @@ -2308,10 +2233,7 @@ int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, const IP_Port *ip */ int add_tcp_relay(Net_Crypto *c, const IP_Port *ip_port, const uint8_t *public_key) { - pthread_mutex_lock(&c->tcp_mutex); - const int ret = add_tcp_relay_global(c->tcp_c, ip_port, public_key); - pthread_mutex_unlock(&c->tcp_mutex); - return ret; + return add_tcp_relay_global(c->tcp_c, ip_port, public_key); } /** @brief Return a random TCP connection number for use in send_tcp_onion_request. @@ -2322,13 +2244,9 @@ int add_tcp_relay(Net_Crypto *c, const IP_Port *ip_port, const uint8_t *public_k * return TCP connection number on success. * return -1 on failure. */ -int get_random_tcp_con_number(Net_Crypto *c) +int get_random_tcp_con_number(const Net_Crypto *c) { - pthread_mutex_lock(&c->tcp_mutex); - const int ret = get_random_tcp_onion_conn_number(c->tcp_c); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return get_random_tcp_onion_conn_number(c->tcp_c); } /** @brief Put IP_Port of a random onion TCP connection in ip_port. @@ -2336,13 +2254,9 @@ int get_random_tcp_con_number(Net_Crypto *c) * return true on success. * return false on failure. */ -bool get_random_tcp_conn_ip_port(Net_Crypto *c, IP_Port *ip_port) +bool get_random_tcp_conn_ip_port(const Net_Crypto *c, IP_Port *ip_port) { - pthread_mutex_lock(&c->tcp_mutex); - const bool ret = tcp_get_random_conn_ip_port(c->tcp_c, ip_port); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return tcp_get_random_conn_ip_port(c->tcp_c, ip_port); } /** @brief Send an onion packet via the TCP relay corresponding to tcp_connections_number. @@ -2352,11 +2266,7 @@ bool get_random_tcp_conn_ip_port(Net_Crypto *c, IP_Port *ip_port) */ int send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length) { - pthread_mutex_lock(&c->tcp_mutex); - const int ret = tcp_send_onion_request(c->tcp_c, tcp_connections_number, data, length); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return tcp_send_onion_request(c->tcp_c, tcp_connections_number, data, length); } /** @@ -2371,12 +2281,8 @@ int send_tcp_forward_request(const Logger *logger, Net_Crypto *c, const IP_Port const uint8_t *chain_keys, uint16_t chain_length, const uint8_t *data, uint16_t data_length) { - pthread_mutex_lock(&c->tcp_mutex); - const int ret = tcp_send_forward_request(logger, c->tcp_c, tcp_forwarder, dht_node, - chain_keys, chain_length, data, data_length); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return tcp_send_forward_request(logger, c->tcp_c, tcp_forwarder, dht_node, + chain_keys, chain_length, data, data_length); } /** @brief Copy a maximum of num random TCP relays we are connected to to tcp_relays. @@ -2386,38 +2292,28 @@ int send_tcp_forward_request(const Logger *logger, Net_Crypto *c, const IP_Port * return number of relays copied to tcp_relays on success. * return 0 on failure. */ -unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num) +unsigned int copy_connected_tcp_relays(const Net_Crypto *c, Node_format *tcp_relays, uint16_t num) { if (num == 0) { return 0; } - pthread_mutex_lock(&c->tcp_mutex); - const unsigned int ret = tcp_copy_connected_relays(c->tcp_c, tcp_relays, num); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return tcp_copy_connected_relays(c->tcp_c, tcp_relays, num); } -uint32_t copy_connected_tcp_relays_index(Net_Crypto *c, Node_format *tcp_relays, uint16_t num, uint32_t idx) +uint32_t copy_connected_tcp_relays_index(const Net_Crypto *c, Node_format *tcp_relays, uint16_t num, uint32_t idx) { if (num == 0) { return 0; } - pthread_mutex_lock(&c->tcp_mutex); - const uint32_t ret = tcp_copy_connected_relays_index(c->tcp_c, tcp_relays, num, idx); - pthread_mutex_unlock(&c->tcp_mutex); - - return ret; + return tcp_copy_connected_relays_index(c->tcp_c, tcp_relays, num, idx); } non_null() static void do_tcp(Net_Crypto *c, void *userdata) { - pthread_mutex_lock(&c->tcp_mutex); do_tcp_connections(c->log, c->tcp_c, userdata); - pthread_mutex_unlock(&c->tcp_mutex); for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { const Crypto_Connection *conn = get_crypto_connection(c, i); @@ -2436,9 +2332,7 @@ static void do_tcp(Net_Crypto *c, void *userdata) continue; } - pthread_mutex_lock(&c->tcp_mutex); set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, !direct_connected); - pthread_mutex_unlock(&c->tcp_mutex); } } @@ -2593,15 +2487,12 @@ static int udp_handle_packet(void *object, const IP_Port *source, const uint8_t return -1; } - pthread_mutex_lock(conn->mutex); - if (net_family_is_ipv4(source->ip.family)) { conn->direct_lastrecv_timev4 = mono_time_get(c->mono_time); } else { conn->direct_lastrecv_timev6 = mono_time_get(c->mono_time); } - pthread_mutex_unlock(conn->mutex); return 0; } @@ -2997,26 +2888,16 @@ int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t return -1; } - pthread_mutex_lock(&c->connections_mutex); - ++c->connection_use_counter; - pthread_mutex_unlock(&c->connections_mutex); - Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); int ret = -1; if (conn != nullptr) { - pthread_mutex_lock(conn->mutex); const uint32_t buffer_start = conn->recv_array.buffer_start; const uint32_t buffer_end = conn->send_array.buffer_end; - pthread_mutex_unlock(conn->mutex); ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length); } - pthread_mutex_lock(&c->connections_mutex); - --c->connection_use_counter; - pthread_mutex_unlock(&c->connections_mutex); - return ret; } @@ -3036,9 +2917,7 @@ int crypto_kill(Net_Crypto *c, int crypt_connection_id) send_kill_packet(c, crypt_connection_id); } - pthread_mutex_lock(&c->tcp_mutex); kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); - pthread_mutex_unlock(&c->tcp_mutex); bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id); bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id); @@ -3135,13 +3014,6 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp); set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp); - if (create_recursive_mutex(&temp->tcp_mutex) != 0 || - pthread_mutex_init(&temp->connections_mutex, nullptr) != 0) { - kill_tcp_connections(temp->tcp_c); - mem_delete(mem, temp); - return nullptr; - } - temp->dht = dht; new_keys(temp); @@ -3215,9 +3087,6 @@ void kill_net_crypto(Net_Crypto *c) crypto_kill(c, i); } - pthread_mutex_destroy(&c->tcp_mutex); - pthread_mutex_destroy(&c->connections_mutex); - kill_tcp_connections(c->tcp_c); bs_list_free(&c->ip_port_list); networking_registerhandler(dht_get_net(c->dht), NET_PACKET_COOKIE_REQUEST, nullptr, nullptr); diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 0d817e4315..8368d46e39 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -40,7 +40,6 @@ /** Packets in this range are reserved for AV use. */ #define PACKET_ID_RANGE_LOSSY_START 192 #define PACKET_ID_RANGE_LOSSY_AV_START 192 -#define PACKET_ID_RANGE_LOSSY_AV_SIZE 8 #define PACKET_ID_RANGE_LOSSY_AV_END 199 /** Packets in this range can be used for anything. */ #define PACKET_ID_RANGE_LOSSY_CUSTOM_START 200 @@ -311,7 +310,7 @@ int add_tcp_relay(Net_Crypto *c, const IP_Port *ip_port, const uint8_t *public_k * return -1 on failure. */ non_null() -int get_random_tcp_con_number(Net_Crypto *c); +int get_random_tcp_con_number(const Net_Crypto *c); /** @brief Put IP_Port of a random onion TCP connection in ip_port. * @@ -319,7 +318,7 @@ int get_random_tcp_con_number(Net_Crypto *c); * return false on failure. */ non_null() -bool get_random_tcp_conn_ip_port(Net_Crypto *c, IP_Port *ip_port); +bool get_random_tcp_conn_ip_port(const Net_Crypto *c, IP_Port *ip_port); /** @brief Send an onion packet via the TCP relay corresponding to tcp_connections_number. * @@ -351,7 +350,7 @@ int send_tcp_forward_request(const Logger *logger, Net_Crypto *c, const IP_Port * return 0 on failure. */ non_null() -unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num); +unsigned int copy_connected_tcp_relays(const Net_Crypto *c, Node_format *tcp_relays, uint16_t num); /** * Copy a maximum of `max_num` TCP relays we are connected to starting at the index in the TCP relay array @@ -360,7 +359,7 @@ unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, u * Returns the number of relays successfully copied. */ non_null() -uint32_t copy_connected_tcp_relays_index(Net_Crypto *c, Node_format *tcp_relays, uint16_t num, uint32_t idx); +uint32_t copy_connected_tcp_relays_index(const Net_Crypto *c, Node_format *tcp_relays, uint16_t num, uint32_t idx); /** @brief Kill a crypto connection. * diff --git a/toxcore/network.c b/toxcore/network.c index 55aa4e2818..304e048956 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -81,6 +81,10 @@ #include #include +#ifdef HAVE_LIBEV +#include +#endif + #include "attributes.h" #include "bin_pack.h" #include "ccompat.h" @@ -513,6 +517,12 @@ static int sys_listen(void *obj, Socket sock, int backlog) return listen(net_socket_to_native(sock), backlog); } +non_null() +static int sys_connect(void *obj, Socket sock, const Network_Addr *addr) +{ + return connect(net_socket_to_native(sock), (const struct sockaddr *)&addr->addr, addr->size); +} + non_null() static int sys_recvbuf(void *obj, Socket sock) { @@ -586,11 +596,98 @@ static int sys_setsockopt(void *obj, Socket sock, int level, int optname, const return setsockopt(net_socket_to_native(sock), level, optname, (const char *)optval, optlen); } +// sets and fills an array of addrs for address +// returns the number of entries in addrs +non_null() +static int sys_getaddrinfo(void *obj, const Memory *mem, const char *address, int family, int sock_type, Network_Addr **addrs) +{ + assert(addrs != nullptr); + + struct addrinfo hints = {0}; + hints.ai_family = family; + + + // different platforms favour a different field + // hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. + hints.ai_socktype = sock_type; + // hints.ai_protocol = protocol; + + struct addrinfo *infos = nullptr; + + const int rc = getaddrinfo(address, nullptr, &hints, &infos); + + // Lookup failed. + if (rc != 0) { + // TODO(Green-Sky): log error + return 0; + } + + const int32_t max_count = INT32_MAX / sizeof(Network_Addr); + + // we count number of "valid" results + int result = 0; + for (struct addrinfo *walker = infos; walker != nullptr && result < max_count; walker = walker->ai_next) { + if (walker->ai_family == family || family == AF_UNSPEC) { + ++result; + } + + // do we need to check socktype/protocol? + } + + assert(max_count >= result); + + Network_Addr *tmp_addrs = (Network_Addr *)mem_valloc(mem, result, sizeof(Network_Addr)); + if (tmp_addrs == nullptr) { + freeaddrinfo(infos); + return 0; + } + + // now we fill in + int i = 0; + for (struct addrinfo *walker = infos; walker != nullptr; walker = walker->ai_next) { + if (walker->ai_family == family || family == AF_UNSPEC) { + tmp_addrs[i].size = sizeof(struct sockaddr_storage); + tmp_addrs[i].addr.ss_family = walker->ai_family; + + // according to spec, storage is supposed to be large enough (and source shows they are) + // storage is 128 bytes + assert(walker->ai_addrlen <= tmp_addrs[i].size); + + memcpy(&tmp_addrs[i].addr, walker->ai_addr, walker->ai_addrlen); + tmp_addrs[i].size = walker->ai_addrlen; + + ++i; + } + } + + assert(i == result); + + freeaddrinfo(infos); + + *addrs = tmp_addrs; + + // number of entries in addrs + return result; +} + +non_null() +static int sys_freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs) +{ + if (addrs == nullptr) { + return 0; + } + + mem_delete(mem, addrs); + + return 0; +} + static const Network_Funcs os_network_funcs = { sys_close, sys_accept, sys_bind, sys_listen, + sys_connect, sys_recvbuf, sys_recv, sys_recvfrom, @@ -600,8 +697,10 @@ static const Network_Funcs os_network_funcs = { sys_socket_nonblock, sys_getsockopt, sys_setsockopt, + sys_getaddrinfo, + sys_freeaddrinfo, }; -static const Network os_network_obj = {&os_network_funcs}; +static const Network os_network_obj = {&os_network_funcs, nullptr}; const Network *os_network(void) { @@ -882,7 +981,11 @@ bool set_socket_nosigpipe(const Network *ns, Socket sock) bool set_socket_reuseaddr(const Network *ns, Socket sock) { int set = 1; +#if defined(OS_WIN32) + return net_setsockopt(ns, sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &set, sizeof(set)) == 0; +#else return net_setsockopt(ns, sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == 0; +#endif /* OS_WIN32 */ } bool set_socket_dualstack(const Network *ns, Socket sock) @@ -904,6 +1007,13 @@ typedef struct Packet_Handler { void *object; } Packet_Handler; +#ifdef HAVE_LIBEV +typedef struct Networking_Socket_Listener { + ev_io listener; + struct ev_loop *dispatcher; +} Networking_Socket_Listener; +#endif + struct Networking_Core { const Logger *log; const Memory *mem; @@ -914,6 +1024,9 @@ struct Networking_Core { uint16_t port; /* Our UDP socket. */ Socket sock; +#ifdef HAVE_LIBEV + Networking_Socket_Listener sock_listener; +#endif }; Family net_family(const Networking_Core *net) @@ -926,6 +1039,41 @@ uint16_t net_port(const Networking_Core *net) return net->port; } +Socket net_sock(const Networking_Core *net) +{ + return net->sock; +} + +#ifdef HAVE_LIBEV +non_null() +static bool net_ev_is_active(Networking_Core *net) +{ + return ev_is_active(&net->sock_listener.listener) || ev_is_pending(&net->sock_listener.listener); +} + +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data) +{ + if (net_ev_is_active(net)) { + return; + } + + net->sock_listener.dispatcher = dispatcher; + net->sock_listener.listener.data = data; + + ev_io_init(&net->sock_listener.listener, callback, net->sock.sock, EV_READ); + ev_io_start(dispatcher, &net->sock_listener.listener); +} + +void net_ev_stop(Networking_Core *net) +{ + if (!net_ev_is_active(net)) { + return; + } + + ev_io_stop(net->sock_listener.dispatcher, &net->sock_listener.listener); +} +#endif + /* Basic network functions: */ @@ -1386,6 +1534,10 @@ void kill_networking(Networking_Core *net) kill_sock(net->ns, net->sock); } +#ifdef HAVE_LIBEV + net_ev_stop(net); +#endif + mem_delete(net->mem, net); } @@ -1815,37 +1967,34 @@ bool addr_parse_ip(const char *address, IP *to) * prefers v6 if `ip.family` was TOX_AF_UNSPEC and both available * Returns in `*extra` an IPv4 address, if family was TOX_AF_UNSPEC and `*to` is TOX_AF_INET6 * - * @return 0 on failure, `TOX_ADDR_RESOLVE_*` on success. + * @return false on failure, true on success. */ -non_null(1, 2, 3) nullable(4) -static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extra) +non_null(1, 2, 3, 4) nullable(5) +static bool addr_resolve(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if ((true)) { - return 0; + return false; } #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ if (address == nullptr || to == nullptr) { - return 0; + return false; } const Family tox_family = to->family; const int family = make_family(tox_family); - struct addrinfo hints = {0}; - hints.ai_family = family; - hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. - - struct addrinfo *server = nullptr; + Network_Addr *addrs = nullptr; + const int rc = ns->funcs->getaddrinfo(ns->obj, mem, address, family, 0, &addrs); - const int rc = getaddrinfo(address, nullptr, &hints, &server); - - // Lookup failed. - if (rc != 0) { - return 0; + // Lookup failed / empty. + if (rc <= 0) { + return false; } + assert(addrs != nullptr); + IP ip4; ip_init(&ip4, false); // ipv6enabled = false IP ip6; @@ -1854,16 +2003,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr int result = 0; bool done = false; - for (struct addrinfo *walker = server; walker != nullptr && !done; walker = walker->ai_next) { - switch (walker->ai_family) { + for (int i = 0; i < rc && !done; ++i) { + switch (addrs[i].addr.ss_family) { case AF_INET: { - if (walker->ai_family == family) { /* AF_INET requested, done */ - const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr; + if (addrs[i].addr.ss_family == family) { /* AF_INET requested, done */ + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr; get_ip4(&to->ip.v4, &addr->sin_addr); result = TOX_ADDR_RESOLVE_INET; done = true; } else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */ - const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr; + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr; get_ip4(&ip4.ip.v4, &addr->sin_addr); result |= TOX_ADDR_RESOLVE_INET; } @@ -1872,16 +2021,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr } case AF_INET6: { - if (walker->ai_family == family) { /* AF_INET6 requested, done */ - if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { - const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)walker->ai_addr; + if (addrs[i].addr.ss_family == family) { /* AF_INET6 requested, done */ + if (addrs[i].size == sizeof(struct sockaddr_in6)) { + const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr; get_ip6(&to->ip.v6, &addr->sin6_addr); result = TOX_ADDR_RESOLVE_INET6; done = true; } } else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */ - if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { - const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)walker->ai_addr; + if (addrs[i].size == sizeof(struct sockaddr_in6)) { + const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr; get_ip6(&ip6.ip.v6, &addr->sin6_addr); result |= TOX_ADDR_RESOLVE_INET6; } @@ -1906,37 +2055,34 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr } } - freeaddrinfo(server); - return result; + ns->funcs->freeaddrinfo(ns->obj, mem, addrs); + return result != 0; } -bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra) +bool addr_resolve_or_parse_ip(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra, bool dns_enabled) { - if (addr_resolve(ns, address, to, extra) == 0) { - if (!addr_parse_ip(address, to)) { - return false; - } + if (dns_enabled && addr_resolve(ns, mem, address, to, extra)) { + return true; } - return true; + return addr_parse_ip(address, to); } -bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port) +bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port) { - struct sockaddr_storage addr = {0}; - size_t addrsize; + Network_Addr addr = {{0}}; if (net_family_is_ipv4(ip_port->ip.family)) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr; - addrsize = sizeof(struct sockaddr_in); + addr.size = sizeof(struct sockaddr_in); addr4->sin_family = AF_INET; fill_addr4(&ip_port->ip.ip.v4, &addr4->sin_addr); addr4->sin_port = ip_port->port; } else if (net_family_is_ipv6(ip_port->ip.family)) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr; - addrsize = sizeof(struct sockaddr_in6); + addr.size = sizeof(struct sockaddr_in6); addr6->sin6_family = AF_INET6; fill_addr6(&ip_port->ip.ip.v6, &addr6->sin6_addr); addr6->sin6_port = ip_port->port; @@ -1958,7 +2104,7 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por net_socket_to_native(sock), net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port)); errno = 0; - if (connect(net_socket_to_native(sock), (struct sockaddr *)&addr, addrsize) == -1) { + if (ns->funcs->connect(ns->obj, sock, &addr) == -1) { const int error = net_error(); // Non-blocking socket: "Operation in progress" means it's connecting. @@ -1974,7 +2120,7 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por return true; } -int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int tox_type) +int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled) { assert(node != nullptr); @@ -1996,6 +2142,10 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to return 1; } + if (!dns_enabled) { + return -1; + } + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if ((true)) { IP_Port *ip_port = (IP_Port *)mem_alloc(mem, sizeof(IP_Port)); @@ -2010,25 +2160,29 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to } #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ + int type = make_socktype(tox_type); + // ugly + if (tox_type == -1) { + type = 0; + } + // It's not an IP address, so now we try doing a DNS lookup. - struct addrinfo *infos; - const int ret = getaddrinfo(node, nullptr, nullptr, &infos); + Network_Addr *addrs = nullptr; + const int rc = ns->funcs->getaddrinfo(ns->obj, mem, node, AF_UNSPEC, type, &addrs); - if (ret != 0) { + // Lookup failed / empty. + if (rc <= 0) { return -1; } + assert(addrs != nullptr); + // Used to avoid calloc parameter overflow const size_t max_count = min_u64(SIZE_MAX, INT32_MAX) / sizeof(IP_Port); - const int type = make_socktype(tox_type); size_t count = 0; - for (struct addrinfo *cur = infos; count < max_count && cur != nullptr; cur = cur->ai_next) { - if (cur->ai_socktype != 0 && type > 0 && cur->ai_socktype != type) { - continue; - } - - if (cur->ai_family != AF_INET && cur->ai_family != AF_INET6) { + for (int i = 0; i < rc && count < max_count; ++i) { + if (addrs[i].addr.ss_family != AF_INET && addrs[i].addr.ss_family != AF_INET6) { continue; } @@ -2038,40 +2192,36 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to assert(count <= max_count); if (count == 0) { - freeaddrinfo(infos); + ns->funcs->freeaddrinfo(ns->obj, mem, addrs); return 0; } IP_Port *ip_port = (IP_Port *)mem_valloc(mem, count, sizeof(IP_Port)); if (ip_port == nullptr) { - freeaddrinfo(infos); + ns->funcs->freeaddrinfo(ns->obj, mem, addrs); *res = nullptr; return -1; } *res = ip_port; - for (struct addrinfo *cur = infos; cur != nullptr; cur = cur->ai_next) { - if (cur->ai_socktype != 0 && type > 0 && cur->ai_socktype != type) { - continue; - } - - if (cur->ai_family == AF_INET) { - const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)cur->ai_addr; + for (int i = 0; i < rc && count < max_count; ++i) { + if (addrs[i].addr.ss_family == AF_INET) { + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr; ip_port->ip.ip.v4.uint32 = addr->sin_addr.s_addr; - } else if (cur->ai_family == AF_INET6) { - const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cur->ai_addr; + } else if (addrs[i].addr.ss_family == AF_INET6) { + const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)&addrs[i].addr; memcpy(ip_port->ip.ip.v6.uint8, addr->sin6_addr.s6_addr, sizeof(IP6)); } else { continue; } - const Family *const family = make_tox_family(cur->ai_family); + const Family *const family = make_tox_family(addrs[i].addr.ss_family); assert(family != nullptr); if (family == nullptr) { - freeaddrinfo(infos); + ns->funcs->freeaddrinfo(ns->obj, mem, addrs); return -1; } @@ -2080,7 +2230,7 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to ++ip_port; } - freeaddrinfo(infos); + ns->funcs->freeaddrinfo(ns->obj, mem, addrs); return count; } diff --git a/toxcore/network.h b/toxcore/network.h index 06857b8917..2598705767 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -13,6 +13,10 @@ #include // size_t #include // uint*_t +#ifdef HAVE_LIBEV +#include +#endif + #include "attributes.h" #include "bin_pack.h" #include "logger.h" @@ -39,6 +43,7 @@ typedef int net_close_cb(void *obj, Socket sock); typedef Socket net_accept_cb(void *obj, Socket sock); typedef int net_bind_cb(void *obj, Socket sock, const Network_Addr *addr); typedef int net_listen_cb(void *obj, Socket sock, int backlog); +typedef int net_connect_cb(void *obj, Socket sock, const Network_Addr *addr); typedef int net_recvbuf_cb(void *obj, Socket sock); typedef int net_recv_cb(void *obj, Socket sock, uint8_t *buf, size_t len); typedef int net_recvfrom_cb(void *obj, Socket sock, uint8_t *buf, size_t len, Network_Addr *addr); @@ -48,8 +53,8 @@ typedef Socket net_socket_cb(void *obj, int domain, int type, int proto); typedef int net_socket_nonblock_cb(void *obj, Socket sock, bool nonblock); typedef int net_getsockopt_cb(void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen); typedef int net_setsockopt_cb(void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen); -typedef int net_getaddrinfo_cb(void *obj, int family, Network_Addr **addrs); -typedef int net_freeaddrinfo_cb(void *obj, Network_Addr *addrs); +typedef int net_getaddrinfo_cb(void *obj, const Memory *mem, const char *address, int family, int protocol, Network_Addr **addrs); +typedef int net_freeaddrinfo_cb(void *obj, const Memory *mem, Network_Addr *addrs); /** @brief Functions wrapping POSIX network functions. * @@ -61,6 +66,7 @@ typedef struct Network_Funcs { net_accept_cb *accept; net_bind_cb *bind; net_listen_cb *listen; + net_connect_cb *connect; net_recvbuf_cb *recvbuf; net_recv_cb *recv; net_recvfrom_cb *recvfrom; @@ -396,21 +402,23 @@ non_null() void ipport_copy(IP_Port *target, const IP_Port *source); /** - * Resolves string into an IP address + * @brief Resolves string into an IP address. * - * @param address a hostname (or something parseable to an IP address) - * @param to to.family MUST be initialized, either set to a specific IP version + * @param[in,out] ns Network object. + * @param[in] address a hostname (or something parseable to an IP address). + * @param[in,out] to to.family MUST be initialized, either set to a specific IP version * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (0), if both - * IP versions are acceptable - * @param extra can be NULL and is only set in special circumstances, see returns + * IP versions are acceptable. + * @param[out] extra can be NULL and is only set in special circumstances, see returns. + * @param[in] dns_enabled if false, DNS resolution is skipped. * - * Returns in `*to` a matching address (IPv6 or IPv4) - * Returns in `*extra`, if not NULL, an IPv4 address, if `to->family` was TOX_AF_UNSPEC + * Returns in `*to` a matching address (IPv6 or IPv4). + * Returns in `*extra`, if not NULL, an IPv4 address, if `to->family` was `TOX_AF_UNSPEC`. * * @return true on success, false on failure */ -non_null(1, 2, 3) nullable(4) -bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra); +non_null(1, 2, 3, 4) nullable(5) +bool addr_resolve_or_parse_ip(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra, bool dns_enabled); /** @brief Function to receive data, ip and port of sender is put into ip_port. * Packet data is put into data. @@ -424,6 +432,16 @@ non_null() Family net_family(const Networking_Core *net); non_null() uint16_t net_port(const Networking_Core *net); +non_null() +Socket net_sock(const Networking_Core *net); + +#ifdef HAVE_LIBEV +typedef void net_ev_listen_cb(struct ev_loop *dispatcher, ev_io *sock_listener, int events); +non_null() +void net_ev_listen(Networking_Core *net, struct ev_loop *dispatcher, net_ev_listen_cb *callback, void *data); +non_null() +void net_ev_stop(Networking_Core *net); +#endif /** Close the socket. */ non_null() @@ -501,7 +519,7 @@ void networking_poll(const Networking_Core *net, void *userdata); * Return false on failure. */ non_null() -bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port); +bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port); /** @brief High-level getaddrinfo implementation. * @@ -510,14 +528,21 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por * address that can be specified by calling `net_connect()`, the port is ignored. * * Skip all addresses with socktype != type (use type = -1 to get all addresses) - * To correctly deallocate array memory use `net_freeipport()` + * To correctly deallocate array memory use `net_freeipport()`. + * + * @param ns Network object. + * @param mem Memory allocator. + * @param node The node parameter identifies the host or service on which to connect. + * @param[out] res An array of IP_Port structures will be allocated into this pointer. + * @param tox_type The type of socket to use (stream or datagram), only relevant for DNS lookups. + * @param dns_enabled If false, DNS resolution is skipped, when passed a hostname, this function will return an error. * * @return number of elements in res array. * @retval 0 if res array empty. * @retval -1 on error. */ non_null() -int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int tox_type); +int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled); /** Deallocates memory allocated by net_getipport */ non_null(1) nullable(2) diff --git a/toxcore/network_test_util.cc b/toxcore/network_test_util.cc index 758e49500d..c8d2ff3e8a 100644 --- a/toxcore/network_test_util.cc +++ b/toxcore/network_test_util.cc @@ -3,6 +3,7 @@ #include #include "crypto_core.h" +#include "mem.h" #include "network.h" #include "test_util.hh" @@ -11,6 +12,7 @@ Network_Funcs const Network_Class::vtable = { Method::invoke<&Network_Class::accept>, Method::invoke<&Network_Class::bind>, Method::invoke<&Network_Class::listen>, + Method::invoke<&Network_Class::connect>, Method::invoke<&Network_Class::recvbuf>, Method::invoke<&Network_Class::recv>, Method::invoke<&Network_Class::recvfrom>, @@ -34,6 +36,10 @@ int Test_Network::listen(void *obj, Socket sock, int backlog) { return net->funcs->listen(net->obj, sock, backlog); } +int Test_Network::connect(void *obj, Socket sock, const Network_Addr *addr) +{ + return net->funcs->connect(net->obj, sock, addr); +} int Test_Network::recvbuf(void *obj, Socket sock) { return net->funcs->recvbuf(net->obj, sock); } int Test_Network::recv(void *obj, Socket sock, uint8_t *buf, size_t len) { @@ -70,13 +76,14 @@ int Test_Network::setsockopt( { return net->funcs->setsockopt(net->obj, sock, level, optname, optval, optlen); } -int Test_Network::getaddrinfo(void *obj, int family, Network_Addr **addrs) +int Test_Network::getaddrinfo(void *obj, const Memory *mem, const char *address, int family, + int protocol, Network_Addr **addrs) { - return net->funcs->getaddrinfo(net->obj, family, addrs); + return net->funcs->getaddrinfo(net->obj, mem, address, family, protocol, addrs); } -int Test_Network::freeaddrinfo(void *obj, Network_Addr *addrs) +int Test_Network::freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs) { - return net->funcs->freeaddrinfo(net->obj, addrs); + return net->funcs->freeaddrinfo(net->obj, mem, addrs); } Network_Class::~Network_Class() = default; diff --git a/toxcore/network_test_util.hh b/toxcore/network_test_util.hh index 70f238aa92..be967d3d4f 100644 --- a/toxcore/network_test_util.hh +++ b/toxcore/network_test_util.hh @@ -4,6 +4,7 @@ #include #include "crypto_core.h" +#include "mem.h" #include "network.h" #include "test_util.hh" @@ -24,6 +25,7 @@ struct Network_Class { virtual net_accept_cb accept = 0; virtual net_bind_cb bind = 0; virtual net_listen_cb listen = 0; + virtual net_connect_cb connect = 0; virtual net_recvbuf_cb recvbuf = 0; virtual net_recv_cb recv = 0; virtual net_recvfrom_cb recvfrom = 0; @@ -48,6 +50,7 @@ class Test_Network : public Network_Class { Socket accept(void *obj, Socket sock) override; int bind(void *obj, Socket sock, const Network_Addr *addr) override; int listen(void *obj, Socket sock, int backlog) override; + int connect(void *obj, Socket sock, const Network_Addr *addr) override; int recvbuf(void *obj, Socket sock) override; int recv(void *obj, Socket sock, uint8_t *buf, size_t len) override; int recvfrom(void *obj, Socket sock, uint8_t *buf, size_t len, Network_Addr *addr) override; @@ -60,8 +63,9 @@ class Test_Network : public Network_Class { void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen) override; int setsockopt( void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen) override; - int getaddrinfo(void *obj, int family, Network_Addr **addrs) override; - int freeaddrinfo(void *obj, Network_Addr *addrs) override; + int getaddrinfo(void *obj, const Memory *mem, const char *address, int family, int protocol, + Network_Addr **addrs) override; + int freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs) override; }; template <> diff --git a/toxcore/onion.c b/toxcore/onion.c index 9fab57af90..722d610dff 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c @@ -180,7 +180,7 @@ int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_ * return -1 on failure. * return length of created packet on success. */ -int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_length, +int create_onion_packet(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length) { @@ -202,7 +202,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_ ipport_pack(step2, &path->ip_port3); memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); - int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, step1_size, + int len = encrypt_data_symmetric(mem, path->shared_key3, nonce, step1, step1_size, step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { @@ -213,7 +213,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_ VLA(uint8_t, step3, step3_size); ipport_pack(step3, &path->ip_port2); memcpy(step3 + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); - len = encrypt_data_symmetric(path->shared_key2, nonce, step2, step2_size, + len = encrypt_data_symmetric(mem, path->shared_key2, nonce, step2, step2_size, step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { @@ -224,7 +224,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_ memcpy(packet + 1, nonce, CRYPTO_NONCE_SIZE); memcpy(packet + 1 + CRYPTO_NONCE_SIZE, path->public_key1, CRYPTO_PUBLIC_KEY_SIZE); - len = encrypt_data_symmetric(path->shared_key1, nonce, step3, step3_size, + len = encrypt_data_symmetric(mem, path->shared_key1, nonce, step3, step3_size, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); if (len != SIZE_IPPORT + SEND_BASE * 2 + length + CRYPTO_MAC_SIZE) { @@ -243,7 +243,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_ * return -1 on failure. * return length of created packet on success. */ -int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_packet_length, +int create_onion_packet_tcp(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length) { @@ -265,7 +265,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac ipport_pack(step2, &path->ip_port3); memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); - int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, step1_size, + int len = encrypt_data_symmetric(mem, path->shared_key3, nonce, step1, step1_size, step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { @@ -274,7 +274,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac ipport_pack(packet + CRYPTO_NONCE_SIZE, &path->ip_port2); memcpy(packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); - len = encrypt_data_symmetric(path->shared_key2, nonce, step2, step2_size, + len = encrypt_data_symmetric(mem, path->shared_key2, nonce, step2, step2_size, packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { @@ -355,7 +355,7 @@ static int handle_send_initial(void *object, const IP_Port *source, const uint8_ } const int len = decrypt_data_symmetric( - shared_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_length, plain); + onion->mem, shared_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_length, plain); if (len != plaintext_length) { LOGGER_TRACE(onion->log, "decrypt failed: %d != %d", len, plaintext_length); @@ -393,7 +393,7 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, const I uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); uint8_t *ret_part = data + data_len; random_nonce(onion->rng, ret_part); - len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, + len = encrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, ret_part + CRYPTO_NONCE_SIZE); if (len != SIZE_IPPORT + CRYPTO_MAC_SIZE) { @@ -436,7 +436,7 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac return 1; } - int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + int len = decrypt_data_symmetric(onion->mem, shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain); if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1 + CRYPTO_MAC_SIZE)) { @@ -459,7 +459,7 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; ipport_pack(ret_data, source); memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); - len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + len = encrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), ret_part + CRYPTO_NONCE_SIZE); if (len != RETURN_2 - CRYPTO_NONCE_SIZE) { @@ -502,7 +502,7 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac return 1; } - int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + int len = decrypt_data_symmetric(onion->mem, shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain); if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2 + CRYPTO_MAC_SIZE)) { @@ -532,7 +532,7 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; ipport_pack(ret_data, source); memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); - len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + len = encrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), ret_part + CRYPTO_NONCE_SIZE); if (len != RETURN_3 - CRYPTO_NONCE_SIZE) { @@ -574,7 +574,7 @@ static int handle_recv_3(void *object, const IP_Port *source, const uint8_t *pac change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT + RETURN_2]; - const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain); if ((uint32_t)len != sizeof(plain)) { @@ -627,7 +627,7 @@ static int handle_recv_2(void *object, const IP_Port *source, const uint8_t *pac change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT + RETURN_1]; - const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain); if ((uint32_t)len != sizeof(plain)) { @@ -679,7 +679,7 @@ static int handle_recv_1(void *object, const IP_Port *source, const uint8_t *pac change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT]; - const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + const int len = decrypt_data_symmetric(onion->mem, onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, SIZE_IPPORT + CRYPTO_MAC_SIZE, plain); if ((uint32_t)len != SIZE_IPPORT) { diff --git a/toxcore/onion.h b/toxcore/onion.h index a5d3554e7b..ef8fdb7e77 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h @@ -105,7 +105,7 @@ int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_ * return length of created packet on success. */ non_null() -int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_length, +int create_onion_packet(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length); @@ -119,7 +119,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_ * return length of created packet on success. */ non_null() -int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_packet_length, +int create_onion_packet_tcp(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length); diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 593d81aa2c..c7a6b38ad8 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -9,7 +9,6 @@ #include "onion_announce.h" #include -#include #include #include "DHT.h" @@ -23,6 +22,7 @@ #include "network.h" #include "onion.h" #include "shared_key_cache.h" +#include "sort.h" #include "timed_auth.h" #define PING_ID_TIMEOUT ONION_ANNOUNCE_TIMEOUT @@ -103,7 +103,7 @@ void onion_announce_entry_set_time(Onion_Announce *onion_a, uint32_t entry, uint * return -1 on failure. * return packet length on success. */ -int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, +int create_announce_request(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data) { @@ -122,7 +122,7 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac packet[0] = NET_PACKET_ANNOUNCE_REQUEST_OLD; random_nonce(rng, packet + 1); - const int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain), + const int len = encrypt_data(mem, dest_client_id, secret_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); if ((uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE != ONION_ANNOUNCE_REQUEST_MIN_SIZE) { @@ -146,7 +146,7 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac * return -1 on failure. * return 0 on success. */ -int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, +int create_data_request(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) { if (DATA_REQUEST_MIN_SIZE + length > max_packet_length) { @@ -167,7 +167,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_ memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); - const int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length, + const int len = encrypt_data(mem, encrypt_public_key, random_secret_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); if (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len != DATA_REQUEST_MIN_SIZE + @@ -193,14 +193,14 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_ * return 0 on success. */ int send_announce_request( - const Logger *log, const Networking_Core *net, const Random *rng, + const Logger *log, const Memory *mem, const Networking_Core *net, const Random *rng, const Onion_Path *path, const Node_format *dest, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data) { uint8_t request[ONION_ANNOUNCE_REQUEST_MIN_SIZE]; - int len = create_announce_request(rng, request, sizeof(request), dest->public_key, public_key, secret_key, ping_id, + int len = create_announce_request(mem, rng, request, sizeof(request), dest->public_key, public_key, secret_key, ping_id, client_id, data_public_key, sendback_data); if (len != sizeof(request)) { @@ -208,7 +208,7 @@ int send_announce_request( } uint8_t packet[ONION_MAX_PACKET_SIZE]; - len = create_onion_packet(rng, packet, sizeof(packet), path, &dest->ip_port, request, sizeof(request)); + len = create_onion_packet(mem, rng, packet, sizeof(packet), path, &dest->ip_port, request, sizeof(request)); if (len == -1) { return -1; @@ -238,19 +238,19 @@ int send_announce_request( * return 0 on success. */ int send_data_request( - const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, + const Logger *log, const Memory *mem, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) { uint8_t request[ONION_MAX_DATA_SIZE]; - int len = create_data_request(rng, request, sizeof(request), public_key, encrypt_public_key, nonce, data, length); + int len = create_data_request(mem, rng, request, sizeof(request), public_key, encrypt_public_key, nonce, data, length); if (len == -1) { return -1; } uint8_t packet[ONION_MAX_PACKET_SIZE]; - len = create_onion_packet(rng, packet, sizeof(packet), path, dest, request, len); + len = create_onion_packet(mem, rng, packet, sizeof(packet), path, dest, request, len); if (len == -1) { return -1; @@ -281,23 +281,17 @@ static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) return -1; } -typedef struct Cmp_Data { +typedef struct Onion_Announce_Entry_Cmp { + const Memory *mem; const Mono_Time *mono_time; - const uint8_t *base_public_key; - Onion_Announce_Entry entry; -} Cmp_Data; + const uint8_t *comp_public_key; +} Onion_Announce_Entry_Cmp; non_null() -static int cmp_entry(const void *a, const void *b) +static int onion_announce_entry_cmp(const Onion_Announce_Entry_Cmp *cmp, const Onion_Announce_Entry *entry1, const Onion_Announce_Entry *entry2) { - const Cmp_Data *cmp1 = (const Cmp_Data *)a; - const Cmp_Data *cmp2 = (const Cmp_Data *)b; - const Onion_Announce_Entry entry1 = cmp1->entry; - const Onion_Announce_Entry entry2 = cmp2->entry; - const uint8_t *cmp_public_key = cmp1->base_public_key; - - const bool t1 = mono_time_is_timeout(cmp1->mono_time, entry1.announce_time, ONION_ANNOUNCE_TIMEOUT); - const bool t2 = mono_time_is_timeout(cmp1->mono_time, entry2.announce_time, ONION_ANNOUNCE_TIMEOUT); + const bool t1 = mono_time_is_timeout(cmp->mono_time, entry1->announce_time, ONION_ANNOUNCE_TIMEOUT); + const bool t2 = mono_time_is_timeout(cmp->mono_time, entry2->announce_time, ONION_ANNOUNCE_TIMEOUT); if (t1 && t2) { return 0; @@ -311,7 +305,7 @@ static int cmp_entry(const void *a, const void *b) return 1; } - const int closest = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + const int closest = id_closest(cmp->comp_public_key, entry1->public_key, entry2->public_key); if (closest == 1) { return 1; @@ -325,31 +319,80 @@ static int cmp_entry(const void *a, const void *b) } non_null() -static void sort_onion_announce_list(const Memory *mem, const Mono_Time *mono_time, - Onion_Announce_Entry *list, unsigned int length, - const uint8_t *comp_public_key) +static bool onion_announce_entry_less_handler(const void *object, const void *a, const void *b) { - // Pass comp_public_key to qsort with each Client_data entry, so the - // comparison function can use it as the base of comparison. - Cmp_Data *cmp_list = (Cmp_Data *)mem_valloc(mem, length, sizeof(Cmp_Data)); + const Onion_Announce_Entry_Cmp *cmp = (const Onion_Announce_Entry_Cmp *)object; + const Onion_Announce_Entry *entry1 = (const Onion_Announce_Entry *)a; + const Onion_Announce_Entry *entry2 = (const Onion_Announce_Entry *)b; - if (cmp_list == nullptr) { - return; - } + return onion_announce_entry_cmp(cmp, entry1, entry2) < 0; +} - for (uint32_t i = 0; i < length; ++i) { - cmp_list[i].mono_time = mono_time; - cmp_list[i].base_public_key = comp_public_key; - cmp_list[i].entry = list[i]; - } +non_null() +static const void *onion_announce_entry_get_handler(const void *arr, uint32_t index) +{ + const Onion_Announce_Entry *entries = (const Onion_Announce_Entry *)arr; + return &entries[index]; +} + +non_null() +static void onion_announce_entry_set_handler(void *arr, uint32_t index, const void *val) +{ + Onion_Announce_Entry *entries = (Onion_Announce_Entry *)arr; + const Onion_Announce_Entry *entry = (const Onion_Announce_Entry *)val; + entries[index] = *entry; +} - qsort(cmp_list, length, sizeof(Cmp_Data), cmp_entry); +non_null() +static void *onion_announce_entry_subarr_handler(void *arr, uint32_t index, uint32_t size) +{ + Onion_Announce_Entry *entries = (Onion_Announce_Entry *)arr; + return &entries[index]; +} - for (uint32_t i = 0; i < length; ++i) { - list[i] = cmp_list[i].entry; +non_null() +static void *onion_announce_entry_alloc_handler(const void *object, uint32_t size) +{ + const Onion_Announce_Entry_Cmp *cmp = (const Onion_Announce_Entry_Cmp *)object; + Onion_Announce_Entry *tmp = (Onion_Announce_Entry *)mem_valloc(cmp->mem, size, sizeof(Onion_Announce_Entry)); + + if (tmp == nullptr) { + return nullptr; } - mem_delete(mem, cmp_list); + return tmp; +} + +non_null() +static void onion_announce_entry_delete_handler(const void *object, void *arr, uint32_t size) +{ + const Onion_Announce_Entry_Cmp *cmp = (const Onion_Announce_Entry_Cmp *)object; + mem_delete(cmp->mem, arr); +} + +static const Sort_Funcs onion_announce_entry_cmp_funcs = { + onion_announce_entry_less_handler, + onion_announce_entry_get_handler, + onion_announce_entry_set_handler, + onion_announce_entry_subarr_handler, + onion_announce_entry_alloc_handler, + onion_announce_entry_delete_handler, +}; + +non_null() +static void sort_onion_announce_list(const Memory *mem, const Mono_Time *mono_time, + Onion_Announce_Entry *list, unsigned int length, + const uint8_t *comp_public_key) +{ + // Pass comp_public_key to sort with each Onion_Announce_Entry entry, so the + // comparison function can use it as the base of comparison. + const Onion_Announce_Entry_Cmp cmp = { + mem, + mono_time, + comp_public_key, + }; + + merge_sort(list, length, &cmp, &onion_announce_entry_cmp_funcs); } /** @brief add entry to entries list @@ -455,7 +498,7 @@ static int handle_announce_request_common( return 1; } - const int decrypted_len = decrypt_data_symmetric(shared_key, packet + 1, + const int decrypted_len = decrypt_data_symmetric(onion_a->mem, shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, plain_size + CRYPTO_MAC_SIZE, plain); if ((uint32_t)decrypted_len != plain_size) { @@ -542,7 +585,7 @@ static int handle_announce_request_common( offset += extra_size; uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; - const int len = encrypt_data_symmetric(shared_key, nonce, response, offset, + const int len = encrypt_data_symmetric(onion_a->mem, shared_key, nonce, response, offset, data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE); if (len != offset + CRYPTO_MAC_SIZE) { diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index 1158093170..da0e19035a 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -65,7 +65,7 @@ void onion_announce_entry_set_time(Onion_Announce *onion_a, uint32_t entry, uint * return packet length on success. */ non_null() -int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, +int create_announce_request(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data); @@ -82,7 +82,7 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac * return 0 on success. */ non_null() -int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, +int create_data_request(const Memory *mem, const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); /** @brief Create and send an onion announce request packet. @@ -101,7 +101,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_ */ non_null() int send_announce_request( - const Logger *log, const Networking_Core *net, const Random *rng, + const Logger *log, const Memory *mem, const Networking_Core *net, const Random *rng, const Onion_Path *path, const Node_format *dest, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, @@ -125,7 +125,7 @@ int send_announce_request( */ non_null() int send_data_request( - const Logger *log, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, + const Logger *log, const Memory *mem, const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 9b0ac96102..45546cbf0b 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -10,7 +10,6 @@ #include "onion_client.h" #include -#include #include #include "DHT.h" @@ -29,6 +28,7 @@ #include "onion.h" #include "onion_announce.h" #include "ping_array.h" +#include "sort.h" #include "timed_auth.h" #include "util.h" @@ -528,7 +528,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa { if (net_family_is_ipv4(path->ip_port1.ip.family) || net_family_is_ipv6(path->ip_port1.ip.family)) { uint8_t packet[ONION_MAX_PACKET_SIZE]; - const int len = create_onion_packet(onion_c->rng, packet, sizeof(packet), path, dest, data, length); + const int len = create_onion_packet(onion_c->mem, onion_c->rng, packet, sizeof(packet), path, dest, data, length); if (len == -1) { return -1; @@ -545,7 +545,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa if (ip_port_to_tcp_connections_number(&path->ip_port1, &tcp_connections_number)) { uint8_t packet[ONION_MAX_PACKET_SIZE]; - const int len = create_onion_packet_tcp(onion_c->rng, packet, sizeof(packet), path, dest, data, length); + const int len = create_onion_packet_tcp(onion_c->mem, onion_c->rng, packet, sizeof(packet), path, dest, data, length); if (len == -1) { return -1; @@ -661,7 +661,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con if (num == 0) { len = create_announce_request( - onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c), + onion_c->mem, onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c), nc_get_self_secret_key(onion_c->c), ping_id, nc_get_self_public_key(onion_c->c), onion_c->temp_public_key, sendback); } else { @@ -669,14 +669,14 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con if (onion_friend->gc_data_length == 0) { // contact is a friend len = create_announce_request( - onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, + onion_c->mem, onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key, zero_ping_id, sendback); } else { // contact is a gc onion_friend->is_groupchat = true; len = create_gca_announce_request( - onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, + onion_c->mem, onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key, zero_ping_id, sendback, onion_friend->gc_data, onion_friend->gc_data_length); @@ -694,23 +694,17 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len); } -typedef struct Onion_Client_Cmp_Data { +typedef struct Onion_Node_Cmp { + const Memory *mem; const Mono_Time *mono_time; - const uint8_t *base_public_key; - Onion_Node entry; -} Onion_Client_Cmp_Data; + const uint8_t *comp_public_key; +} Onion_Node_Cmp; non_null() -static int onion_client_cmp_entry(const void *a, const void *b) +static int onion_node_cmp(const Onion_Node_Cmp *cmp, const Onion_Node *entry1, const Onion_Node *entry2) { - const Onion_Client_Cmp_Data *cmp1 = (const Onion_Client_Cmp_Data *)a; - const Onion_Client_Cmp_Data *cmp2 = (const Onion_Client_Cmp_Data *)b; - const Onion_Node entry1 = cmp1->entry; - const Onion_Node entry2 = cmp2->entry; - const uint8_t *cmp_public_key = cmp1->base_public_key; - - const bool t1 = onion_node_timed_out(&entry1, cmp1->mono_time); - const bool t2 = onion_node_timed_out(&entry2, cmp2->mono_time); + const bool t1 = onion_node_timed_out(entry1, cmp->mono_time); + const bool t2 = onion_node_timed_out(entry2, cmp->mono_time); if (t1 && t2) { return 0; @@ -724,7 +718,7 @@ static int onion_client_cmp_entry(const void *a, const void *b) return 1; } - const int closest = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + const int closest = id_closest(cmp->comp_public_key, entry1->public_key, entry2->public_key); if (closest == 1) { return 1; @@ -738,30 +732,79 @@ static int onion_client_cmp_entry(const void *a, const void *b) } non_null() -static void sort_onion_node_list(const Memory *mem, const Mono_Time *mono_time, - Onion_Node *list, unsigned int length, const uint8_t *comp_public_key) +static bool onion_node_less_handler(const void *object, const void *a, const void *b) { - // Pass comp_public_key to qsort with each Client_data entry, so the - // comparison function can use it as the base of comparison. - Onion_Client_Cmp_Data *cmp_list = (Onion_Client_Cmp_Data *)mem_valloc(mem, length, sizeof(Onion_Client_Cmp_Data)); + const Onion_Node_Cmp *cmp = (const Onion_Node_Cmp *)object; + const Onion_Node *entry1 = (const Onion_Node *)a; + const Onion_Node *entry2 = (const Onion_Node *)b; - if (cmp_list == nullptr) { - return; - } + return onion_node_cmp(cmp, entry1, entry2) < 0; +} - for (uint32_t i = 0; i < length; ++i) { - cmp_list[i].mono_time = mono_time; - cmp_list[i].base_public_key = comp_public_key; - cmp_list[i].entry = list[i]; - } +non_null() +static const void *onion_node_get_handler(const void *arr, uint32_t index) +{ + const Onion_Node *entries = (const Onion_Node *)arr; + return &entries[index]; +} - qsort(cmp_list, length, sizeof(Onion_Client_Cmp_Data), onion_client_cmp_entry); +non_null() +static void onion_node_set_handler(void *arr, uint32_t index, const void *val) +{ + Onion_Node *entries = (Onion_Node *)arr; + const Onion_Node *entry = (const Onion_Node *)val; + entries[index] = *entry; +} + +non_null() +static void *onion_node_subarr_handler(void *arr, uint32_t index, uint32_t size) +{ + Onion_Node *entries = (Onion_Node *)arr; + return &entries[index]; +} - for (uint32_t i = 0; i < length; ++i) { - list[i] = cmp_list[i].entry; +non_null() +static void *onion_node_alloc_handler(const void *object, uint32_t size) +{ + const Onion_Node_Cmp *cmp = (const Onion_Node_Cmp *)object; + Onion_Node *tmp = (Onion_Node *)mem_valloc(cmp->mem, size, sizeof(Onion_Node)); + + if (tmp == nullptr) { + return nullptr; } - mem_delete(mem, cmp_list); + return tmp; +} + +non_null() +static void onion_node_delete_handler(const void *object, void *arr, uint32_t size) +{ + const Onion_Node_Cmp *cmp = (const Onion_Node_Cmp *)object; + mem_delete(cmp->mem, arr); +} + +static const Sort_Funcs onion_node_cmp_funcs = { + onion_node_less_handler, + onion_node_get_handler, + onion_node_set_handler, + onion_node_subarr_handler, + onion_node_alloc_handler, + onion_node_delete_handler, +}; + +non_null() +static void sort_onion_node_list(const Memory *mem, const Mono_Time *mono_time, + Onion_Node *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to sort with each Onion_Node entry, so the + // comparison function can use it as the base of comparison. + const Onion_Node_Cmp cmp = { + mem, + mono_time, + comp_public_key, + }; + + merge_sort(list, length, &cmp, &onion_node_cmp_funcs); } non_null() @@ -955,14 +998,14 @@ static int handle_announce_response(void *object, const IP_Port *source, const u } uint8_t plain[1 + ONION_PING_ID_SIZE + ONION_ANNOUNCE_RESPONSE_MAX_SIZE - ONION_ANNOUNCE_RESPONSE_MIN_SIZE]; - const int plain_size = 1 + ONION_PING_ID_SIZE + length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; + const uint32_t plain_size = 1 + ONION_PING_ID_SIZE + length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; int len; const uint16_t nonce_start = 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH; const uint16_t ciphertext_start = nonce_start + CRYPTO_NONCE_SIZE; const uint16_t ciphertext_size = length - ciphertext_start; if (num == 0) { - len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c), + len = decrypt_data(onion_c->mem, public_key, nc_get_self_secret_key(onion_c->c), &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); } else { if (!onion_c->friends_list[num - 1].is_valid) { @@ -970,7 +1013,7 @@ static int handle_announce_response(void *object, const IP_Port *source, const u return 1; } - len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, + len = decrypt_data(onion_c->mem, public_key, onion_c->friends_list[num - 1].temp_secret_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); } @@ -1066,7 +1109,7 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con const uint16_t ciphertext_size = length - ciphertext_start; if (num == 0) { - len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c), + len = decrypt_data(onion_c->mem, public_key, nc_get_self_secret_key(onion_c->c), &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); } else { if (!onion_c->friends_list[num - 1].is_valid) { @@ -1074,7 +1117,7 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con return 1; } - len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, + len = decrypt_data(onion_c->mem, public_key, onion_c->friends_list[num - 1].temp_secret_key, &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); } @@ -1136,7 +1179,7 @@ static int handle_data_response(void *object, const IP_Port *source, const uint8 const uint16_t temp_plain_size = length - ONION_DATA_RESPONSE_MIN_SIZE; VLA(uint8_t, temp_plain, temp_plain_size); - int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1, + int len = decrypt_data(onion_c->mem, packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain); @@ -1146,7 +1189,7 @@ static int handle_data_response(void *object, const IP_Port *source, const uint8 const uint16_t plain_size = temp_plain_size - DATA_IN_RESPONSE_MIN_SIZE; VLA(uint8_t, plain, plain_size); - len = decrypt_data(temp_plain, nc_get_self_secret_key(onion_c->c), + len = decrypt_data(onion_c->mem, temp_plain, nc_get_self_secret_key(onion_c->c), packet + 1, temp_plain + CRYPTO_PUBLIC_KEY_SIZE, temp_plain_size - CRYPTO_PUBLIC_KEY_SIZE, plain); @@ -1305,7 +1348,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, const uint16_t packet_size = DATA_IN_RESPONSE_MIN_SIZE + length; VLA(uint8_t, packet, packet_size); memcpy(packet, nc_get_self_public_key(onion_c->c), CRYPTO_PUBLIC_KEY_SIZE); - int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, + int len = encrypt_data(onion_c->mem, onion_c->friends_list[friend_num].real_public_key, nc_get_self_secret_key(onion_c->c), nonce, data, length, packet + CRYPTO_PUBLIC_KEY_SIZE); @@ -1324,7 +1367,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint8_t o_packet[ONION_MAX_PACKET_SIZE]; len = create_data_request( - onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, + onion_c->mem, onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, node_list[good_nodes[i]].data_public_key, nonce, packet, packet_size); if (len == -1) { @@ -1364,7 +1407,7 @@ static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uin VLA(uint8_t, temp, temp_size); memcpy(temp, nc_get_self_public_key(onion_c->c), CRYPTO_PUBLIC_KEY_SIZE); memcpy(temp + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); - int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, + int len = encrypt_data(onion_c->mem, onion_c->friends_list[friend_num].real_public_key, nc_get_self_secret_key(onion_c->c), nonce, data, length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); @@ -1374,7 +1417,7 @@ static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uin uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE]; len = create_request( - onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data, + onion_c->mem, onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data, onion_c->friends_list[friend_num].dht_public_key, temp, temp_size, CRYPTO_PACKET_DHTPK); assert(len <= UINT16_MAX); const Packet packet = {packet_data, (uint16_t)len}; @@ -1401,7 +1444,7 @@ static int handle_dht_dhtpk(void *object, const IP_Port *source, const uint8_t * } uint8_t plain[DHTPK_DATA_MAX_LENGTH]; - const int len = decrypt_data(packet, nc_get_self_secret_key(onion_c->c), + const int len = decrypt_data(onion_c->mem, packet, nc_get_self_secret_key(onion_c->c), packet + CRYPTO_PUBLIC_KEY_SIZE, packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain); diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 61e4e6fd1c..92be110322 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h @@ -183,6 +183,8 @@ non_null() unsigned int onion_getfriend_dht_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); #define ONION_DATA_IN_RESPONSE_MIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) + +// TODO(Jfreegman): This is not the correct value; data this large will be dropped by the onion client. #define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) /** @brief Send data of length length to friendnum. diff --git a/toxcore/ping.c b/toxcore/ping.c index 303c418cea..d3dc92d584 100644 --- a/toxcore/ping.c +++ b/toxcore/ping.c @@ -31,6 +31,7 @@ struct Ping { const Mono_Time *mono_time; const Random *rng; + const Memory *mem; DHT *dht; Ping_Array *ping_array; @@ -72,7 +73,7 @@ void ping_send_request(Ping *ping, const IP_Port *ipp, const uint8_t *public_key pk_copy(pk + 1, dht_get_self_public_key(ping->dht)); // Our pubkey random_nonce(ping->rng, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce - rc = encrypt_data_symmetric(shared_key, + rc = encrypt_data_symmetric(ping->mem, shared_key, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, ping_plain, sizeof(ping_plain), pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); @@ -104,7 +105,7 @@ static int ping_send_response(const Ping *ping, const IP_Port *ipp, const uint8_ random_nonce(ping->rng, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey - const int rc = encrypt_data_symmetric(shared_encryption_key, + const int rc = encrypt_data_symmetric(ping->mem, shared_encryption_key, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, ping_plain, sizeof(ping_plain), pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); @@ -137,7 +138,7 @@ static int handle_ping_request(void *object, const IP_Port *source, const uint8_ uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id - const int rc = decrypt_data_symmetric(shared_key, + const int rc = decrypt_data_symmetric(ping->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, @@ -182,7 +183,7 @@ static int handle_ping_response(void *object, const IP_Port *source, const uint8 uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id - rc = decrypt_data_symmetric(shared_key, + rc = decrypt_data_symmetric(ping->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, @@ -348,6 +349,7 @@ Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Random *rng, ping->mono_time = mono_time; ping->rng = rng; + ping->mem = mem; ping->dht = dht; networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_REQUEST, &handle_ping_request, dht); networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_RESPONSE, &handle_ping_response, dht); diff --git a/toxcore/sort.c b/toxcore/sort.c new file mode 100644 index 0000000000..45b2ffa3ab --- /dev/null +++ b/toxcore/sort.c @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +#include "sort.h" + +#include + +#include "attributes.h" +#include "ccompat.h" +#include "util.h" + +/** + * @brief Threshold for when to switch to insertion sort. + * + * This is a trade-off between the complexity of insertion sort and the + * overhead of merge sort. The threshold is chosen to be the smallest value + * that gives a measurable speedup for insertion sort over merge sort. This is + * based on measurements done in sort_bench.cc. Starting from 32 elements, + * merge sort is faster than insertion sort in all our tests (both unsorted + * and mostly-sorted). + * + * Toxcore has a lot of small arrays it wants to sort, so this optimisation + * makes sense. + */ +#define SMALL_ARRAY_THRESHOLD 16 + +non_null() +static void merge_sort_merge_back( + void *arr, + const void *l_arr, uint32_t l_arr_size, + const void *r_arr, uint32_t r_arr_size, + uint32_t left_start, + const void *object, const Sort_Funcs *funcs) +{ + uint32_t li = 0; + uint32_t ri = 0; + uint32_t k = left_start; + + while (li < l_arr_size && ri < r_arr_size) { + const void *l = funcs->get_callback(l_arr, li); + const void *r = funcs->get_callback(r_arr, ri); + // !(r < l) <=> (r >= l) <=> (l <= r) + if (!funcs->less_callback(object, r, l)) { + funcs->set_callback(arr, k, l); + ++li; + } else { + funcs->set_callback(arr, k, r); + ++ri; + } + ++k; + } + + /* Copy the remaining elements of `l_arr[]`, if there are any. */ + while (li < l_arr_size) { + funcs->set_callback(arr, k, funcs->get_callback(l_arr, li)); + ++li; + ++k; + } + + /* Copy the remaining elements of `r_arr[]`, if there are any. */ + while (ri < r_arr_size) { + funcs->set_callback(arr, k, funcs->get_callback(r_arr, ri)); + ++ri; + ++k; + } +} + +/** Function to merge the two haves `arr[left_start..mid]` and `arr[mid+1..right_end]` of array `arr[]`. */ +non_null() +static void merge_sort_merge( + void *arr, uint32_t left_start, uint32_t mid, uint32_t right_end, void *tmp, + const void *object, const Sort_Funcs *funcs) +{ + const uint32_t l_arr_size = mid - left_start + 1; + const uint32_t r_arr_size = right_end - mid; + + /* Temporary arrays, using the tmp buffer created in `merge_sort` below. */ + void *l_arr = funcs->subarr_callback(tmp, 0, l_arr_size); + void *r_arr = funcs->subarr_callback(tmp, l_arr_size, r_arr_size); + + /* Copy data to temp arrays `l_arr[]` and `r_arr[]`. + * + * This is iterating and repeatedly calling `get` and `set`, which sounds + * slow, but is only marginally slower than having a `copy` callback. With + * a `copy` callback, we'd save 3-4% in time. + */ + for (uint32_t i = 0; i < l_arr_size; ++i) { + funcs->set_callback(l_arr, i, funcs->get_callback(arr, left_start + i)); + } + for (uint32_t i = 0; i < r_arr_size; ++i) { + funcs->set_callback(r_arr, i, funcs->get_callback(arr, mid + 1 + i)); + } + + /* Merge the temp arrays back into `arr[left_start..right_end]`. */ + merge_sort_merge_back(arr, l_arr, l_arr_size, r_arr, r_arr_size, left_start, object, funcs); +} + +non_null() +static void insertion_sort_step(void *arr, void *tmp, uint32_t i, const void *object, const Sort_Funcs *funcs) +{ + funcs->set_callback(tmp, 0, funcs->get_callback(arr, i)); + uint32_t j = i; + + while (j > 0) { + if (!funcs->less_callback(object, tmp, funcs->get_callback(arr, j - 1))) { + break; + } + funcs->set_callback(arr, j, funcs->get_callback(arr, j - 1)); + --j; + } + + funcs->set_callback(arr, j, tmp); +} + +non_null() +static void insertion_sort_with_buf(void *arr, uint32_t arr_size, void *tmp, uint32_t tmp_size, const void *object, const Sort_Funcs *funcs) +{ + for (uint32_t i = 1; i < arr_size; ++i) { + insertion_sort_step(arr, tmp, i, object, funcs); + } +} + +non_null() +static bool insertion_sort(void *arr, uint32_t arr_size, const void *object, const Sort_Funcs *funcs) +{ + void *tmp = funcs->alloc_callback(object, 1); + + if (tmp == nullptr) { + return false; + } + + insertion_sort_with_buf(arr, arr_size, tmp, 1, object, funcs); + + funcs->delete_callback(object, tmp, 1); + return true; +} + +void merge_sort_with_buf(void *arr, uint32_t arr_size, void *tmp, uint32_t tmp_size, const void *object, const Sort_Funcs *funcs) +{ + assert(tmp_size >= arr_size); + + if (arr_size <= SMALL_ARRAY_THRESHOLD) { + assert(tmp_size >= 1); + insertion_sort_with_buf(arr, arr_size, tmp, tmp_size, object, funcs); + return; + } + + // Merge subarrays in bottom up manner. First merge subarrays of + // size 1 to create sorted subarrays of size 2, then merge subarrays + // of size 2 to create sorted subarrays of size 4, and so on. + for (uint32_t curr_size = 1; curr_size <= arr_size - 1; curr_size = 2 * curr_size) { + // Pick starting point of different subarrays of current size + for (uint32_t left_start = 0; left_start < arr_size - 1; left_start += 2 * curr_size) { + // Find ending point of left subarray. mid+1 is starting + // point of right + const uint32_t mid = min_u32(left_start + curr_size - 1, arr_size - 1); + const uint32_t right_end = min_u32(left_start + 2 * curr_size - 1, arr_size - 1); + + // Merge Subarrays arr[left_start...mid] & arr[mid+1...right_end] + merge_sort_merge(arr, left_start, mid, right_end, tmp, object, funcs); + } + } +} + +bool merge_sort(void *arr, uint32_t arr_size, const void *object, const Sort_Funcs *funcs) +{ + if (arr_size <= SMALL_ARRAY_THRESHOLD) { + return insertion_sort(arr, arr_size, object, funcs); + } + + void *tmp = funcs->alloc_callback(object, arr_size); + + if (tmp == nullptr) { + return false; + } + + merge_sort_with_buf(arr, arr_size, tmp, arr_size, object, funcs); + + funcs->delete_callback(object, tmp, arr_size); + return true; +} diff --git a/toxcore/sort.h b/toxcore/sort.h new file mode 100644 index 0000000000..c84d77694c --- /dev/null +++ b/toxcore/sort.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +#ifndef C_TOXCORE_TOXCORE_SORT_H +#define C_TOXCORE_TOXCORE_SORT_H + +#include +#include + +#include "attributes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Compare elements with a less-than ordering: `a < b`. */ +typedef bool sort_less_cb(const void *object, const void *a, const void *b); +/** @brief Get element from array at index. */ +typedef const void *sort_get_cb(const void *arr, uint32_t index); +/** @brief Set element in array at index to new value (perform copy). */ +typedef void sort_set_cb(void *arr, uint32_t index, const void *val); +/** @brief Get a sub-array at an index of a given size (mutable pointer). + * + * Used to index in the temporary array allocated by `sort_alloc_cb` and get + * a sub-array for working memory. + */ +typedef void *sort_subarr_cb(void *arr, uint32_t index, uint32_t size); +/** @brief Allocate a new array of the element type. + * + * @param size The array size in elements of type T (not byte size). This value + * is always exactly the input array size as passed to `merge_sort`. + */ +typedef void *sort_alloc_cb(const void *object, uint32_t size); +/** @brief Free the element type array. */ +typedef void sort_delete_cb(const void *object, void *arr, uint32_t size); + +/** @brief Virtual function table for getting/setting elements in an array and + * comparing them. + * + * Only the `less`, `alloc`, and `delete` functions get a `this`-pointer. We + * assume that indexing in an array doesn't need any other information than the + * array itself. + * + * For now, the `this`-pointer is const, because we assume sorting doesn't need + * to mutate any state, but if necessary that can be changed in the future. + */ +typedef struct Sort_Funcs { + sort_less_cb *less_callback; + sort_get_cb *get_callback; + sort_set_cb *set_callback; + sort_subarr_cb *subarr_callback; + sort_alloc_cb *alloc_callback; + sort_delete_cb *delete_callback; +} Sort_Funcs; + +/** @brief Non-recursive merge sort function to sort `arr[0...arr_size-1]`. + * + * Avoids `memcpy` and avoids treating elements as byte arrays. Instead, uses + * callbacks to index in arrays and copy elements. This makes it quite a bit + * slower than `qsort`, but works with elements that require special care when + * being copied (e.g. if they are part of a graph or other data structure that + * with pointers or other invariants). + * + * This function actually uses insertion sort for small arrays (up to 16 + * elements), which is faster than merge sort for small arrays, especially + * when mostly sorted (a common use case in toxcore). + * + * Allocates a single temporary array with the provided alloc callback, and + * frees it at the end. This is significantly faster than an in-place + * implementation. + * + * Complexity: + * - Space: `O(n) where n = array_size`. + * - Time: `O(n * log n) where n = array_size`. + * + * Compared to `qsort`, this is about 60-70% slower for large arrays. For small + * arrays (up to 16 elements), it's about 50% faster than `qsort`. + * + * @param[in,out] arr An array of type T. + * @param arr_size Number of elements in @p arr (count, not byte size). + * @param[in] object Comparator object. + * @param[in] funcs Callback struct for elements of type T. + */ +non_null() +bool merge_sort(void *arr, uint32_t arr_size, const void *object, const Sort_Funcs *funcs); + +/** + * @brief Merge sort like above but with a pre-allocated buffer. + * + * This function is the same as `merge_sort` but uses a pre-allocated buffer + * for temporary storage. This can be useful if the caller wants to avoid + * dynamic memory allocation. + * + * This function is 1-2% faster than `merge_sort` for small arrays up to 1000 + * elements, and about 5-10% faster for large arrays (2000+ elements). + * + * The main upside is that `alloc` and `delete` callbacks don't need to be + * implemented, and the caller can use a stack-allocated buffer. + * + * @param[in,out] arr An array of type T. + * @param arr_size Number of elements in @p arr (count, not byte size). + * @param[in,out] tmp A buffer of size `tmp_size` for temporary storage. + * @param tmp_size Number of elements in @p tmp (count, not byte size). Must be + * at least as large as `arr_size`. + * @param[in] object Comparator object. + * @param[in] funcs Callback struct for elements of type T. + */ +non_null() +void merge_sort_with_buf(void *arr, uint32_t arr_size, void *tmp, uint32_t tmp_size, const void *object, const Sort_Funcs *funcs); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* C_TOXCORE_TOXCORE_SORT_H */ diff --git a/toxcore/sort_bench.cc b/toxcore/sort_bench.cc new file mode 100644 index 0000000000..0e75bc9559 --- /dev/null +++ b/toxcore/sort_bench.cc @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +#include + +#include +#include +#include +#include + +#include "mem.h" +#include "sort.h" +#include "sort_test_util.hh" + +namespace { + +std::pair, std::mt19937> random_vec(benchmark::State &state) +{ + std::mt19937 rng; + // INT_MAX-1 so later we have room to add 1 larger element if needed. + std::uniform_int_distribution dist{ + std::numeric_limits::min(), std::numeric_limits::max() - 1}; + + std::vector vec(state.range(0)); + std::generate(std::begin(vec), std::end(vec), [&]() { + std::array compare_value; + std::generate( + std::begin(compare_value), std::end(compare_value), [&]() { return dist(rng); }); + return Some_Type{nullptr, compare_value, "hello there"}; + }); + + return {vec, rng}; +} + +std::vector mostly_sorted_vec(benchmark::State &state) +{ + auto [vec, rng] = random_vec(state); + std::sort(vec.begin(), vec.end()); + + // Randomly swap 5% of the vector. + std::uniform_int_distribution dist{0, vec.size() - 1}; + for (std::size_t i = 0; i < vec.size() / 20; ++i) { + const auto a = dist(rng); + const auto b = dist(rng); + std::swap(vec[a], vec[b]); + } + + return vec; +} + +void BM_merge_sort(benchmark::State &state) +{ + const auto vec = random_vec(state).first; + + for (auto _ : state) { + auto unsorted = vec; + merge_sort(unsorted.data(), unsorted.size(), &state, &Some_Type::funcs); + } +} + +BENCHMARK(BM_merge_sort)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_merge_sort_with_buf(benchmark::State &state) +{ + const auto vec = random_vec(state).first; + std::vector buf(vec.size()); + + for (auto _ : state) { + auto unsorted = vec; + merge_sort_with_buf( + unsorted.data(), unsorted.size(), buf.data(), buf.size(), &state, &Some_Type::funcs); + } +} + +BENCHMARK(BM_merge_sort_with_buf)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_merge_sort_mostly_sorted(benchmark::State &state) +{ + auto vec = mostly_sorted_vec(state); + + for (auto _ : state) { + auto unsorted = vec; + merge_sort(unsorted.data(), unsorted.size(), &state, &Some_Type::funcs); + } +} + +BENCHMARK(BM_merge_sort_mostly_sorted)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_qsort(benchmark::State &state) +{ + const auto vec = random_vec(state).first; + + for (auto _ : state) { + auto unsorted = vec; + qsort(unsorted.data(), unsorted.size(), sizeof(unsorted[0]), my_type_cmp); + } +} + +BENCHMARK(BM_qsort)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_qsort_mostly_sorted(benchmark::State &state) +{ + auto vec = mostly_sorted_vec(state); + + for (auto _ : state) { + auto unsorted = vec; + qsort(unsorted.data(), unsorted.size(), sizeof(unsorted[0]), my_type_cmp); + } +} + +BENCHMARK(BM_qsort_mostly_sorted)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_std_sort(benchmark::State &state) +{ + const auto vec = random_vec(state).first; + + for (auto _ : state) { + auto unsorted = vec; + std::sort(unsorted.begin(), unsorted.end()); + } +} + +BENCHMARK(BM_std_sort)->RangeMultiplier(2)->Range(8, 8 << 8); + +void BM_std_sort_mostly_sorted(benchmark::State &state) +{ + auto vec = mostly_sorted_vec(state); + + for (auto _ : state) { + auto unsorted = vec; + std::sort(unsorted.begin(), unsorted.end()); + } +} + +BENCHMARK(BM_std_sort_mostly_sorted)->RangeMultiplier(2)->Range(8, 8 << 8); + +} + +BENCHMARK_MAIN(); diff --git a/toxcore/sort_test.cc b/toxcore/sort_test.cc new file mode 100644 index 0000000000..c8af3346ab --- /dev/null +++ b/toxcore/sort_test.cc @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +#include "sort.h" + +#include + +#include +#include + +#include "sort_test_util.hh" + +namespace { + +TEST(MergeSort, BehavesLikeStdSort) +{ + std::mt19937 rng; + // INT_MAX-1 so later we have room to add 1 larger element if needed. + std::uniform_int_distribution dist{ + std::numeric_limits::min(), std::numeric_limits::max() - 1}; + + constexpr auto int_funcs = sort_funcs(); + + // Test with int arrays. + for (uint32_t i = 1; i < 500; ++i) { + std::vector vec(i); + std::generate(std::begin(vec), std::end(vec), [&]() { return dist(rng); }); + + auto sorted = vec; + std::sort(sorted.begin(), sorted.end(), std::less()); + + // If vec was accidentally sorted, add another larger element that almost definitely makes + // it not sorted. + if (vec == sorted) { + int const largest = *std::prev(sorted.end()) + 1; + sorted.push_back(largest); + vec.insert(vec.begin(), largest); + } + ASSERT_NE(vec, sorted); + + // Just pass some arbitrary "self" to make sure the callbacks pass it through. + ASSERT_TRUE(merge_sort(vec.data(), vec.size(), &i, &int_funcs)); + ASSERT_EQ(vec, sorted); + } +} + +TEST(MergeSort, WorksWithNonTrivialTypes) +{ + std::mt19937 rng; + std::uniform_int_distribution dist{ + std::numeric_limits::min(), std::numeric_limits::max()}; + + constexpr auto string_funcs = sort_funcs(); + + // Test with std::string arrays. + for (uint32_t i = 1; i < 500; ++i) { + std::vector vec(i); + std::generate(std::begin(vec), std::end(vec), [&]() { return std::to_string(dist(rng)); }); + + auto sorted = vec; + std::sort(sorted.begin(), sorted.end(), std::less()); + + // If vec was accidentally sorted, add another larger element that almost definitely makes + // it not sorted. + if (vec == sorted) { + std::string const largest = "larger than largest int"; + sorted.push_back(largest); + vec.insert(vec.begin(), largest); + } + ASSERT_NE(vec, sorted); + + // Just pass some arbitrary "self" to make sure the callbacks pass it through. + ASSERT_TRUE(merge_sort(vec.data(), vec.size(), &i, &string_funcs)); + ASSERT_EQ(vec, sorted); + } +} + +} // namespace diff --git a/toxcore/sort_test_util.cc b/toxcore/sort_test_util.cc new file mode 100644 index 0000000000..ed85127754 --- /dev/null +++ b/toxcore/sort_test_util.cc @@ -0,0 +1,32 @@ +#include "sort_test_util.hh" + +#include +#include + +#include "sort.h" +#include "util.h" + +namespace { +template +int cmp_uint_array(const std::array &a, const std::array &b) +{ + for (std::size_t i = 0; i < a.size(); ++i) { + const int cmp = cmp_uint(a[i], b[i]); + if (cmp != 0) { + return cmp; + } + } + return 0; +} +} + +const Sort_Funcs Some_Type::funcs = sort_funcs(); + +int my_type_cmp(const void *va, const void *vb) +{ + const auto *a = static_cast(va); + const auto *b = static_cast(vb); + return cmp_uint_array(a->compare_value, b->compare_value); +} + +bool operator<(const Some_Type &a, const Some_Type &b) { return a.compare_value < b.compare_value; } diff --git a/toxcore/sort_test_util.hh b/toxcore/sort_test_util.hh new file mode 100644 index 0000000000..8013290963 --- /dev/null +++ b/toxcore/sort_test_util.hh @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2023-2024 The TokTok team. + */ + +#ifndef C_TOXCORE_TOXCORE_SORT_TEST_UTIL_H +#define C_TOXCORE_TOXCORE_SORT_TEST_UTIL_H + +#include + +#include "sort.h" + +struct Memory; + +template +constexpr Sort_Funcs sort_funcs() +{ + return { + [](const void *object, const void *va, const void *vb) { + const T *a = static_cast(va); + const T *b = static_cast(vb); + + return *a < *b; + }, + [](const void *arr, uint32_t index) -> const void * { + const T *vec = static_cast(arr); + return &vec[index]; + }, + [](void *arr, uint32_t index, const void *val) { + T *vec = static_cast(arr); + const T *value = static_cast(val); + vec[index] = *value; + }, + [](void *arr, uint32_t index, uint32_t size) -> void * { + T *vec = static_cast(arr); + return &vec[index]; + }, + [](const void *object, uint32_t size) -> void * { return new T[size]; }, + [](const void *object, void *arr, uint32_t size) { delete[] static_cast(arr); }, + }; +} + +// A realistic test case where we have a struct with some stuff and an expensive value we compare. +struct Some_Type { + const Memory *mem; + std::array compare_value; + const char *name; + + static const Sort_Funcs funcs; +}; + +int my_type_cmp(const void *va, const void *vb); +bool operator<(const Some_Type &a, const Some_Type &b); + +#endif // C_TOXCORE_TOXCORE_SORT_TEST_UTIL_H diff --git a/toxcore/tox.c b/toxcore/tox.c index 7943167a71..cf834ef59c 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -15,6 +15,18 @@ #include #include +#include + +#ifdef HAVE_LIBEV +#include +#else +#if defined (WIN32) || defined(_WIN32) || defined(__WIN32__) +#include +#else +#include +#endif // WIN32 || _WIN32 || __WIN32__ +#endif // !HAVE_LIBEV + #include "DHT.h" #include "Messenger.h" #include "TCP_client.h" @@ -712,7 +724,8 @@ static int tox_load(Tox *tox, const uint8_t *data, uint32_t length) length - cookie_len, STATE_COOKIE_TYPE); } -Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) +nullable(1, 2, 3) +static Tox *tox_new_system(const struct Tox_Options *options, Tox_Err_New *error, const Tox_System *sys) { struct Tox_Options *default_options = nullptr; @@ -736,7 +749,6 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) const struct Tox_Options *const opts = options != nullptr ? options : default_options; assert(opts != nullptr); - const Tox_System *sys = tox_options_get_operating_system(opts); const Tox_System default_system = tox_default_system(); if (sys == nullptr) { @@ -752,6 +764,8 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) Messenger_Options m_options = {false}; + m_options.dns_enabled = !tox_options_get_experimental_disable_dns(opts); + bool load_savedata_sk = false; bool load_savedata_tox = false; @@ -855,9 +869,10 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) } const char *const proxy_host = tox_options_get_proxy_host(opts); + const bool dns_enabled = !tox_options_get_experimental_disable_dns(opts); if (proxy_host == nullptr - || !addr_resolve_or_parse_ip(tox->sys.ns, proxy_host, &m_options.proxy_info.ip_port.ip, nullptr)) { + || !addr_resolve_or_parse_ip(tox->sys.ns, tox->sys.mem, proxy_host, &m_options.proxy_info.ip_port.ip, nullptr, dns_enabled)) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain. mem_delete(sys->mem, tox); @@ -868,6 +883,18 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts)); } +#ifdef HAVE_LIBEV + tox->dispatcher = ev_loop_new(0); + + if (tox->dispatcher == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); + tox_options_free(default_options); + mem_delete(sys->mem, tox); + return nullptr; + } + +#endif // HAVE_LIBEV + tox->mono_time = mono_time_new(tox->sys.mem, sys->mono_time_callback, sys->mono_time_user_data); if (tox->mono_time == nullptr) { @@ -1020,17 +1047,53 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) return tox; } +Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error) +{ + return tox_new_system(options, error, nullptr); +} + +Tox *tox_new_testing(const Tox_Options *options, Tox_Err_New *error, const Tox_Options_Testing *testing, Tox_Err_New_Testing *testing_error) +{ + if (testing == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL); + SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL); + return nullptr; + } + + if (testing->operating_system == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL); + SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL); + return nullptr; + } + + const Tox_System *sys = testing->operating_system; + + if (sys->rng == nullptr || sys->ns == nullptr || sys->mem == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL); + SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL); + return nullptr; + } + + SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_OK); + return tox_new_system(options, error, sys); +} + void tox_kill(Tox *tox) { if (tox == nullptr) { return; } + tox_loop_stop(tox); + tox_lock(tox); - LOGGER_ASSERT(tox->m->log, tox->m->msi_packet == nullptr, "Attempted to kill tox while toxav is still alive"); + LOGGER_ASSERT(tox->m->log, tox->toxav_object == nullptr, "Attempted to kill tox while toxav is still alive"); kill_groupchats(tox->m->conferences_object); kill_messenger(tox->m); mono_time_free(tox->sys.mem, tox->mono_time); +#ifdef HAVE_LIBEV + ev_loop_destroy(tox->dispatcher); +#endif tox_unlock(tox); if (tox->mutex != nullptr) { @@ -1108,7 +1171,7 @@ static int32_t resolve_bootstrap_node(Tox *tox, const char *host, uint16_t port, return -1; } - const int32_t count = net_getipport(tox->sys.mem, host, root, TOX_SOCK_DGRAM); + const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, host, root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled); if (count < 1) { LOGGER_DEBUG(tox->m->log, "could not resolve bootstrap node '%s'", host); @@ -1265,6 +1328,278 @@ void tox_iterate(Tox *tox, void *user_data) tox_unlock(tox); } +void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback) +{ + assert(tox != nullptr); + tox->loop_begin_callback = callback; +} + +void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback) +{ + assert(tox != nullptr); + tox->loop_end_callback = callback; +} + +#ifdef HAVE_LIBEV + +non_null() +static void tox_stop_loop_async(struct ev_loop *dispatcher, ev_async *listener, int events) +{ + if (dispatcher == nullptr || listener == nullptr) { + return; + } + + const struct Tox_Userdata *tox_data = (const struct Tox_Userdata *)listener->data; + + const Messenger *m = tox_data->tox->m; + + // Stop TCP listeners. + const uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); + + for (uint32_t i = 0; i < len; ++i) { + const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); + + assert(conn != nullptr); + tcp_con_ev_stop(conn->connection); + } + + // Stop UDP listener. + net_ev_stop(m->net); + + ev_async_stop(dispatcher, listener); + + ev_break(dispatcher, EVBREAK_ALL); +} + +non_null() +static void tox_do_iterate(struct ev_loop *dispatcher, ev_io *sock_listener, int events) +{ + if (dispatcher == nullptr || sock_listener == nullptr) { + return; + } + + struct Tox_Userdata *tox_data = (struct Tox_Userdata *)sock_listener->data; + + const Messenger *m = tox_data->tox->m; + + if (tox_data->tox->loop_begin_callback) { + tox_data->tox->loop_begin_callback(tox_data->tox, tox_data->user_data); + } + + tox_iterate(tox_data->tox, tox_data->user_data); + + // Start TCP listeners. + const uint32_t len = tcp_connections_length(nc_get_tcp_c(m->net_crypto)); + + for (uint32_t i = 0; i < len; ++i) { + const TCP_con *conn = tcp_connections_connection_at(nc_get_tcp_c(m->net_crypto), i); + + assert(conn != nullptr); + tcp_con_ev_listen(conn->connection, dispatcher, tox_do_iterate, tox_data); + } + + // Start UDP listener. + net_ev_listen(m->net, dispatcher, tox_do_iterate, tox_data); + + if (tox_data->tox->loop_end_callback) { + tox_data->tox->loop_end_callback(tox_data->tox, tox_data->user_data); + } +} + +bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) +{ + assert(tox != nullptr); + + struct Tox_Userdata tox_data = { tox, user_data }; + + ev_async_init(&tox->stop_loop, tox_stop_loop_async); + tox->stop_loop.data = &tox_data; + ev_async_start(tox->dispatcher, &tox->stop_loop); + + ev_io stub_listener; + ev_init(&stub_listener, tox_do_iterate); + stub_listener.data = &tox_data; + tox_do_iterate(tox->dispatcher, &stub_listener, 0); + + if (ev_run(tox->dispatcher, 0) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_BREAK); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); + return true; +} + +void tox_loop_stop(Tox *tox) +{ + assert(tox != nullptr); + tox_lock(tox); + ev_async_send(tox->dispatcher, &tox->stop_loop); + tox_unlock(tox); +} + +#else // !HAVE_LIBEV + +non_null() +static bool realloc_sockets(const Memory *mem, Socket **sockets_ptr, uint32_t *sockets_num, uint32_t fd_count) +{ + if (*sockets_num == fd_count) { + // No need to resize. + return true; + } + + Socket *new_sockets = (Socket *)mem_vrealloc(mem, *sockets_ptr, fd_count, sizeof(Socket)); + + if (new_sockets == nullptr) { + return false; + } + + *sockets_ptr = new_sockets; + *sockets_num = fd_count; + + return true; +} + +/** + * Gathers a list of every network file descriptor on which we expect + * I/O activity (the UDP socket and all TCP sockets). + * + * @param sockets_ptr a pointer to an array (the pointed array can be NULL). + * @param sockets_num the number of current known sockets (will be updated by the funciton). + * + * @return false on allocation error, true on success + */ +non_null() +static bool tox_loop_get_fds(const Messenger *m, Socket **sockets_ptr, uint32_t *sockets_num) +{ + assert(m != nullptr); + assert(sockets_ptr != nullptr); + assert(sockets_num != nullptr); + + const TCP_Connections *tcp_c = nc_get_tcp_c(m->net_crypto); + + const uint32_t tcp_count = tcp_connections_length(tcp_c); + const uint32_t fd_count = tcp_count + 1; // tcp_count TCP sockets + 1 UDP socket + + if (!realloc_sockets(m->mem, sockets_ptr, sockets_num, fd_count)) { + return false; + } + + Socket *sockets = *sockets_ptr; + + // Add the TCP sockets. + for (uint32_t i = 0; i < tcp_count; ++i) { + const TCP_con *conn = tcp_connections_connection_at(tcp_c, i); + + assert(conn != nullptr); + sockets[i] = tcp_con_sock(conn->connection); + } + + // Add the one UDP socket. + sockets[fd_count - 1] = net_sock(m->net); + + return true; +} + +non_null() +static bool locked_get(const Tox *tox, const bool *value) +{ + tox_lock(tox); + const bool res = *value; + tox_unlock(tox); + return res; +} + +non_null() +static void locked_set(const Tox *tox, bool *value, bool new_value) +{ + tox_lock(tox); + *value = new_value; + tox_unlock(tox); +} + +non_null() +static bool tox_loop_select(Tox *tox, Socket *fdlist, uint32_t fdcount) +{ + fd_set readable; + FD_ZERO(&readable); + + Socket maxfd = net_socket_from_native(0); + + for (uint32_t i = 0; i < fdcount; ++i) { + const int sock = net_socket_to_native(fdlist[i]); + if (sock == 0) { + continue; + } + + FD_SET(sock, &readable); + + if (sock > net_socket_to_native(maxfd)) { + maxfd = fdlist[i]; + } + } + + struct timeval timeout; + + // TODO(cleverca22): use a longer timeout. + timeout.tv_sec = 0; + + timeout.tv_usec = (suseconds_t)(tox_iteration_interval(tox) * 1000 * 2); + + return select(net_socket_to_native(maxfd), &readable, nullptr, nullptr, &timeout) >= 0 || errno == EBADF; +} + +bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error) +{ + assert(tox != nullptr); + + Messenger *m = tox->m; + + uint32_t fdcount = 0; + Socket *fdlist = nullptr; + + locked_set(tox, &tox->loop_run, true); + + while (locked_get(tox, &tox->loop_run)) { + if (tox->loop_begin_callback != nullptr) { + tox->loop_begin_callback(tox, user_data); + } + + tox_iterate(tox, user_data); + + // TODO(cleverca22): should we call loop_end_callback() on error? + if (tox->loop_end_callback != nullptr) { + tox->loop_end_callback(tox, user_data); + } + + if (!tox_loop_get_fds(m, &fdlist, &fdcount)) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_GET_FDS); + mem_delete(m->mem, fdlist); + return false; + } + + if (!tox_loop_select(tox, fdlist, fdcount)) { + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_SELECT); + mem_delete(m->mem, fdlist); + return false; + } + } + + SET_ERROR_PARAMETER(error, TOX_ERR_LOOP_OK); + + mem_delete(m->mem, fdlist); + + return true; +} + +void tox_loop_stop(Tox *tox) +{ + assert(tox != nullptr); + locked_set(tox, &tox->loop_run, false); +} + +#endif // !HAVE_LIBEV + void tox_self_get_address(const Tox *tox, uint8_t address[TOX_ADDRESS_SIZE]) { assert(tox != nullptr); @@ -2520,6 +2855,12 @@ uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *co Tox_Err_Conference_Join *error) { assert(tox != nullptr); + + if (cookie == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_NULL); + return UINT32_MAX; + } + tox_lock(tox); const int ret = join_groupchat(tox->m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length); tox_unlock(tox); @@ -3209,7 +3550,7 @@ bool tox_group_reconnect(Tox *tox, uint32_t group_number, Tox_Err_Group_Reconnec return false; } - const int ret = gc_rejoin_group(tox->m->group_handler, chat); + const int ret = gc_rejoin_group(tox->m->group_handler, chat, nullptr, 0); tox_unlock(tox); switch (ret) { @@ -3932,7 +4273,7 @@ bool tox_group_get_password(const Tox *tox, uint32_t group_number, uint8_t *pass } Tox_Group_Message_Id tox_group_send_message( - const Tox *tox, uint32_t group_number, Tox_Message_Type type, const uint8_t *message, + const Tox *tox, uint32_t group_number, Tox_Message_Type message_type, const uint8_t *message, size_t length, Tox_Err_Group_Send_Message *error) { assert(tox != nullptr); @@ -3953,7 +4294,7 @@ Tox_Group_Message_Id tox_group_send_message( } uint32_t message_id = 0; - const int ret = gc_send_message(chat, message, length, type, &message_id); + const int ret = gc_send_message(chat, message, length, message_type, &message_id); tox_unlock(tox); switch (ret) { @@ -3995,7 +4336,7 @@ Tox_Group_Message_Id tox_group_send_message( } Tox_Group_Message_Id tox_group_send_private_message(const Tox *tox, uint32_t group_number, uint32_t peer_id, - Tox_Message_Type type, const uint8_t *message, size_t length, Tox_Err_Group_Send_Private_Message *error) + Tox_Message_Type message_type, const uint8_t *message, size_t length, Tox_Err_Group_Send_Private_Message *error) { assert(tox != nullptr); @@ -4015,7 +4356,7 @@ Tox_Group_Message_Id tox_group_send_private_message(const Tox *tox, uint32_t gro } uint32_t message_id = 0; - const int ret = gc_send_private_message(chat, gc_peer_id_from_int(peer_id), type, message, length, &message_id); + const int ret = gc_send_private_message(chat, gc_peer_id_from_int(peer_id), message_type, message, length, &message_id); tox_unlock(tox); switch (ret) { @@ -4232,6 +4573,11 @@ uint32_t tox_group_invite_accept(Tox *tox, uint32_t friend_number, const uint8_t { assert(tox != nullptr); + if (invite_data == nullptr || name == nullptr) { + SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_NULL); + return UINT32_MAX; + } + tox_lock(tox); const int ret = gc_accept_invite(tox->m->group_handler, friend_number, invite_data, length, name, name_length, password, password_length); @@ -4269,7 +4615,7 @@ uint32_t tox_group_invite_accept(Tox *tox, uint32_t friend_number, const uint8_t } case -6: { - SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_CORE); + SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_FRIEND_NOT_FOUND); return UINT32_MAX; } diff --git a/toxcore/tox.h b/toxcore/tox.h index a0f4d20690..825d0f1af6 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013 Tox project. */ @@ -25,9 +25,8 @@ * could not perform any operation, because one of the required parameters was * NULL. Some functions operate correctly or are defined as effectless on NULL. * - * Some functions additionally return a value outside their - * return type domain, or a bool containing true on success and false on - * failure. + * Some functions additionally return a value outside their return type domain, + * or a bool containing true on success and false on failure. * * All functions that take a Tox instance pointer will cause undefined behaviour * when passed a NULL Tox pointer. @@ -52,17 +51,9 @@ * event listeners, it needs to implement the dispatch functionality itself. * * The last argument to a callback is the user data pointer. It is passed from - * tox_iterate to each callback in sequence. - * - * The user data pointer is never stored or dereferenced by any library code, so - * can be any pointer, including NULL. Callbacks must all operate on the same - * object type. In the apidsl code (tox.in.h), this is denoted with `any`. The - * `any` in tox_iterate must be the same `any` as in all callbacks. In C, - * lacking parametric polymorphism, this is a pointer to void. - * - * Old style callbacks that are registered together with a user data pointer - * receive that pointer as argument when they are called. They can each have - * their own user data pointer of their own type. + * tox_iterate to each callback in sequence. The user data pointer is never + * stored or dereferenced by any library code, so can be any pointer, including + * NULL. * * @section threading Threading implications * @@ -157,7 +148,7 @@ uint32_t tox_version_minor(void); * Incremented when bugfixes are applied without changing any functionality or * API or ABI. */ -#define TOX_VERSION_PATCH 18 +#define TOX_VERSION_PATCH 20 uint32_t tox_version_patch(void); @@ -206,7 +197,7 @@ bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch); * * The values of these are not part of the ABI. Prefer to use the function * versions of them for code that should remain compatible with future versions - * of toxcore. + * of the Tox library. */ /** @@ -283,7 +274,7 @@ uint32_t tox_max_status_message_length(void); * * @deprecated The macro will be removed in 0.3.0. Use the function instead. */ -#define TOX_MAX_FRIEND_REQUEST_LENGTH 1016 +#define TOX_MAX_FRIEND_REQUEST_LENGTH 921 uint32_t tox_max_friend_request_length(void); @@ -468,12 +459,12 @@ typedef enum Tox_Log_Level { TOX_LOG_LEVEL_INFO, /** - * Warnings about events_alloc inconsistency or logic errors. + * Warnings about internal inconsistency or logic errors. */ TOX_LOG_LEVEL_WARNING, /** - * Severe unexpected errors caused by external or events_alloc inconsistency. + * Severe unexpected errors caused by external or internal inconsistency. */ TOX_LOG_LEVEL_ERROR, @@ -482,7 +473,7 @@ typedef enum Tox_Log_Level { const char *tox_log_level_to_string(Tox_Log_Level value); /** - * @brief This event is triggered when the toxcore library logs an events_alloc message. + * @brief This event is triggered when Tox logs an internal message. * * This is mostly useful for debugging. This callback can be called from any * function, not just tox_iterate. This means the user data lifetime must at @@ -505,15 +496,6 @@ const char *tox_log_level_to_string(Tox_Log_Level value); typedef void tox_log_cb(Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, const char *message, void *user_data); -/** - * @brief Operating system functions used by Tox. - * - * This struct is opaque and generally shouldn't be used in clients, but in - * combination with tox_private.h, it allows tests to inject non-IO (hermetic) - * versions of low level network, RNG, and time keeping functions. - */ -typedef struct Tox_System Tox_System; - /** * @brief This struct contains all the startup options for Tox. * @@ -546,10 +528,11 @@ struct Tox_Options { * Enable the use of UDP communication when available. * * Setting this to false will force Tox to use TCP only. Communications will - * need to be relayed through a TCP relay node, potentially slowing them down. + * need to be relayed through a TCP relay node, potentially slowing them + * down. * - * If a proxy is enabled, UDP will be disabled if either toxcore or the - * proxy don't support proxying UDP messages. + * If a proxy is enabled, UDP will be disabled if either the Tox library or + * the proxy don't support proxying UDP messages. */ bool udp_enabled; @@ -576,10 +559,11 @@ struct Tox_Options { * The IP address or DNS name of the proxy to be used. * * If used, this must be non-NULL and be a valid DNS name. The name must not - * exceed TOX_MAX_HOSTNAME_LENGTH characters, and be in a NUL-terminated C string - * format (TOX_MAX_HOSTNAME_LENGTH includes the NUL byte). + * exceed TOX_MAX_HOSTNAME_LENGTH characters, and be in a NUL-terminated C + * string format (TOX_MAX_HOSTNAME_LENGTH includes the NUL byte). * - * This member is ignored (it can be NULL) if proxy_type is TOX_PROXY_TYPE_NONE. + * This member is ignored (it can be NULL) if proxy_type is + * TOX_PROXY_TYPE_NONE. * * The data pointed at by this member is owned by the user, so must * outlive the options object. @@ -603,8 +587,8 @@ struct Tox_Options { * If either start_port or end_port is 0 while the other is non-zero, the * non-zero port will be the only port in the range. * - * Having start_port > end_port will yield the same behavior as if start_port - * and end_port were swapped. + * Having start_port > end_port will yield the same behavior as if + * start_port and end_port were swapped. */ uint16_t start_port; @@ -627,7 +611,7 @@ struct Tox_Options { uint16_t tcp_port; /** - * Enables or disables UDP hole-punching in toxcore. (Default: enabled). + * Enables or disables UDP hole-punching. (Default: enabled). */ bool hole_punching_enabled; @@ -639,8 +623,8 @@ struct Tox_Options { /** * The savedata. * - * The data pointed at by this member is owned by the user, so must - * outlive the options object. + * The data pointed at by this member is owned by the user, so must outlive + * the options object. */ const uint8_t *savedata_data; @@ -650,7 +634,7 @@ struct Tox_Options { size_t savedata_length; /** - * Logging callback for the new tox instance. + * Logging callback for the new Tox instance. */ tox_log_cb *log_callback; @@ -673,14 +657,9 @@ struct Tox_Options { bool experimental_thread_safety; /** - * Low level operating system functionality such as send/recv, random - * number generation, and memory allocation. - */ - const Tox_System *operating_system; - - /** - * Enable saving DHT-based group chats to Tox save data (via `tox_get_savedata`). - * This format will change in the future, so don't rely on it. + * Enable saving DHT-based group chats to Tox save data (via + * `tox_get_savedata`). This format will change in the future, so don't rely + * on it. * * As an alternative, clients can save the group chat ID in client-owned * savedata. Then, when the client starts, it can use `tox_group_join` @@ -689,6 +668,24 @@ struct Tox_Options { * Default: false. */ bool experimental_groups_persistence; + + /** + * @brief Disable DNS hostname resolution. + * + * Hostnames or IP addresses are passed to the bootstrap/add_tcp_relay + * function and proxy host options. If disabled (this flag is true), only + * IP addresses are allowed. + * + * If this is set to true, the library will not attempt to resolve + * hostnames. This is useful for clients that want to resolve hostnames + * themselves and pass the resolved IP addresses to the library (e.g. in + * case it wants to use Tor). + * Passing hostnames will result in a TOX_ERR_BOOTSTRAP_BAD_HOST error if + * this is set to true. + * + * Default: false. May become true in the future (0.3.0). + */ + bool experimental_disable_dns; }; bool tox_options_get_ipv6_enabled(const Tox_Options *options); @@ -759,14 +756,14 @@ bool tox_options_get_experimental_thread_safety(const Tox_Options *options); void tox_options_set_experimental_thread_safety(Tox_Options *options, bool experimental_thread_safety); -const Tox_System *tox_options_get_operating_system(const Tox_Options *options); - -void tox_options_set_operating_system(Tox_Options *options, const Tox_System *operating_system); - bool tox_options_get_experimental_groups_persistence(const Tox_Options *options); void tox_options_set_experimental_groups_persistence(Tox_Options *options, bool experimental_groups_persistence); +bool tox_options_get_experimental_disable_dns(const Tox_Options *options); + +void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns); + /** * @brief Initialises a Tox_Options object with the default options. * @@ -837,15 +834,16 @@ typedef enum Tox_Err_New { TOX_ERR_NEW_NULL, /** - * The function was unable to allocate enough memory to store the events_alloc - * structures for the Tox object. + * The function was unable to allocate enough memory to store the + * internal structures for the Tox object. */ TOX_ERR_NEW_MALLOC, /** * The function was unable to bind to a port. This may mean that all ports * have already been bound, e.g. by other Tox instances, or it may mean - * a permission error. You may be able to gather more information from errno. + * a permission error. You may be able to gather more information from + * errno. */ TOX_ERR_NEW_PORT_ALLOC, @@ -913,7 +911,7 @@ Tox *tox_new(const Tox_Options *options, Tox_Err_New *error); void tox_kill(Tox *tox); /** - * @brief Calculates the number of bytes required to store the tox instance with + * @brief Calculates the number of bytes required to store the Tox instance with * tox_get_savedata. * * This function cannot fail. The result is always greater than 0. @@ -923,11 +921,12 @@ void tox_kill(Tox *tox); size_t tox_get_savedata_size(const Tox *tox); /** - * @brief Store all information associated with the tox instance to a byte array. + * @brief Store all information associated with the Tox instance to a byte + * array. * - * @param savedata A memory region large enough to store the tox instance - * data. Call tox_get_savedata_size to find the number of bytes required. If this parameter - * is NULL, this function has no effect. + * @param savedata A memory region large enough to store the Tox instance + * data. Call tox_get_savedata_size to find the number of bytes required. If + * this parameter is NULL, this function has no effect. */ void tox_get_savedata(const Tox *tox, uint8_t savedata[]); @@ -1065,17 +1064,84 @@ typedef void tox_self_connection_status_cb(Tox *tox, Tox_Connection connection_s void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback); /** - * @brief Return the time in milliseconds before `tox_iterate()` should be called again - * for optimal performance. + * @brief Return the time in milliseconds before `tox_iterate()` should be + * called again for optimal performance. */ uint32_t tox_iteration_interval(const Tox *tox); /** - * @brief The main loop that needs to be run in intervals of `tox_iteration_interval()` - * milliseconds. + * @brief The main loop that needs to be run in intervals of + * `tox_iteration_interval()` milliseconds. + * @param user_data Any pointer a client wishes the Tox instance to pass into + * the event callbacks, including NULL. */ void tox_iterate(Tox *tox, void *user_data); + +/** + * Error codes for `tox_loop()`. + */ +typedef enum Tox_Err_Loop { + + /** + * The function returned successfully. + */ + TOX_ERR_LOOP_OK, + + /** + * Failed running events dispatcher. + */ + TOX_ERR_LOOP_BREAK, + + /** + * Failed running `select()`. + */ + TOX_ERR_LOOP_SELECT, + + /** + * Failed getting sockets file descriptors. + */ + TOX_ERR_LOOP_GET_FDS, + +} Tox_Err_Loop; + + +/** + * Run `tox_iterate()` any time a packet arrives, returns after `tox_loop_stop()` or `tox_kill()`. + */ +bool tox_loop(Tox *tox, void *user_data, Tox_Err_Loop *error); + +/** + * Tell `tox_loop()` to return. + */ +void tox_loop_stop(Tox *tox); + +/** + * No extra parameters. + */ +typedef void tox_loop_begin_cb(Tox *tox, void *user_data); + + +/** + * Set the callback for the `loop_begin` event. Pass NULL to unset. + * + * This callback is invoked when `tox_loop()` calls into `tox_iterate()`, the client can lock a mutex here. + */ +void tox_callback_loop_begin(Tox *tox, tox_loop_begin_cb *callback); + +/** + * No extra parameters. + */ +typedef void tox_loop_end_cb(Tox *tox, void *user_data); + + +/** + * Set the callback for the `loop_end` event. Pass NULL to unset. + * + * This callback is invoked when `tox_loop()` is finished with `tox_iterate()`, the client can unlock the mutex here. + */ +void tox_callback_loop_end(Tox *tox, tox_loop_end_cb *callback); + /** @} */ /** @{ @@ -1172,7 +1238,8 @@ const char *tox_err_set_info_to_string(Tox_Err_Set_Info value); bool tox_self_set_name(Tox *tox, const uint8_t name[], size_t length, Tox_Err_Set_Info *error); /** - * @brief Return the length of the current nickname as passed to tox_self_set_name. + * @brief Return the length of the current nickname as passed to + * tox_self_set_name. * * If no nickname was set before calling this function, the name is empty, * and this function returns 0. @@ -1206,7 +1273,8 @@ bool tox_self_set_status_message( Tox *tox, const uint8_t status_message[], size_t length, Tox_Err_Set_Info *error); /** - * @brief Return the length of the current status message as passed to tox_self_set_status_message. + * @brief Return the length of the current status message as passed to + * tox_self_set_status_message. * * If no status message was set before calling this function, the status * is empty, and this function returns 0. @@ -1216,13 +1284,14 @@ bool tox_self_set_status_message( size_t tox_self_get_status_message_size(const Tox *tox); /** - * @brief Write the status message set by tox_self_set_status_message to a byte array. + * @brief Write the status message set by tox_self_set_status_message to a byte + * array. * * If no status message was set before calling this function, the status is * empty, and this function has no effect. * - * Call tox_self_get_status_message_size to find out how much memory to allocate for - * the result. + * Call tox_self_get_status_message_size to find out how much memory to allocate + * for the result. * * @param status_message A valid memory location large enough to hold the * status message. If this parameter is NULL, the function has no effect. @@ -1279,8 +1348,8 @@ typedef enum Tox_Err_Friend_Add { TOX_ERR_FRIEND_ADD_OWN_KEY, /** - * A friend request has already been sent, or the address belongs to a friend - * that is already on the friend list. + * A friend request has already been sent, or the address belongs to a + * friend that is already on the friend list. */ TOX_ERR_FRIEND_ADD_ALREADY_SENT, @@ -1360,7 +1429,8 @@ typedef enum Tox_Err_Friend_Delete { TOX_ERR_FRIEND_DELETE_OK, /** - * There was no friend with the given friend number. No friends were deleted. + * There was no friend with the given friend number. No friends were + * deleted. */ TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND, @@ -1411,14 +1481,15 @@ const char *tox_err_friend_by_public_key_to_string(Tox_Err_Friend_By_Public_Key /** * @brief Return the friend number associated with that Public Key. * - * @return the friend number on success, an unspecified value on failure. * @param public_key A byte array containing the Public Key. + * + * @return the friend number on success, an unspecified value on failure. */ Tox_Friend_Number tox_friend_by_public_key(const Tox *tox, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Friend_By_Public_Key *error); /** - * @brief Checks if a friend with the given friend number exists and returns true if - * it does. + * @brief Checks if a friend with the given friend number exists and returns + * true if it does. */ bool tox_friend_exists(const Tox *tox, Tox_Friend_Number friend_number); @@ -1433,7 +1504,8 @@ size_t tox_self_get_friend_list_size(const Tox *tox); /** * @brief Copy a list of valid friend numbers into an array. * - * Call tox_self_get_friend_list_size to determine the number of elements to allocate. + * Call tox_self_get_friend_list_size to determine the number of elements to + * allocate. * * @param friend_list A memory region with enough space to hold the friend * list. If this parameter is NULL, this function has no effect. @@ -1457,7 +1529,8 @@ typedef enum Tox_Err_Friend_Get_Public_Key { const char *tox_err_friend_get_public_key_to_string(Tox_Err_Friend_Get_Public_Key value); /** - * @brief Copies the Public Key associated with a given friend number to a byte array. + * @brief Copies the Public Key associated with a given friend number to a byte + * array. * * @param friend_number The friend number you want the Public Key of. * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If @@ -1486,8 +1559,8 @@ typedef enum Tox_Err_Friend_Get_Last_Online { const char *tox_err_friend_get_last_online_to_string(Tox_Err_Friend_Get_Last_Online value); /** - * @brief Return a unix-time timestamp of the last time the friend associated with a given - * friend number was seen online. + * @brief Return a unix-time timestamp of the last time the friend associated + * with a given friend number was seen online. * * This function will return UINT64_MAX on error. * @@ -1514,8 +1587,9 @@ typedef enum Tox_Err_Friend_Query { /** * The pointer parameter for storing the query result (name, message) was - * NULL. Unlike the `_self_` variants of these functions, which have no effect - * when a parameter is NULL, these functions return an error in that case. + * NULL. Unlike the `_self_` variants of these functions, which have no + * effect when a parameter is NULL, these functions return an error in that + * case. */ TOX_ERR_FRIEND_QUERY_NULL, @@ -1540,8 +1614,8 @@ size_t tox_friend_get_name_size( const Tox *tox, Tox_Friend_Number friend_number, Tox_Err_Friend_Query *error); /** - * @brief Write the name of the friend designated by the given friend number to a byte - * array. + * @brief Write the name of the friend designated by the given friend number to + * a byte array. * * Call tox_friend_get_name_size to determine the allocation size for the `name` * parameter. @@ -1579,22 +1653,23 @@ void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback); /** * @brief Return the length of the friend's status message. * - * If the friend number isinvalid, the return value is SIZE_MAX. + * If the friend number is invalid, the return value is SIZE_MAX. */ size_t tox_friend_get_status_message_size( const Tox *tox, Tox_Friend_Number friend_number, Tox_Err_Friend_Query *error); /** - * @brief Write the status message of the friend designated by the given friend number to a byte - * array. + * @brief Write the status message of the friend designated by the given friend + * number to a byte array. * - * Call tox_friend_get_status_message_size to determine the allocation size for the `status_message` - * parameter. + * Call tox_friend_get_status_message_size to determine the allocation size for + * the `status_message` parameter. * - * The data written to `status_message` is equal to the data received by the last - * `friend_status_message` callback. + * The data written to `status_message` is equal to the data received by the + * last `friend_status_message` callback. * - * @param status_message A valid memory region large enough to store the friend's status message. + * @param status_message A valid memory region large enough to store the + * friend's status message. */ bool tox_friend_get_status_message( const Tox *tox, Tox_Friend_Number friend_number, uint8_t status_message[], @@ -1604,7 +1679,8 @@ bool tox_friend_get_status_message( * @param friend_number The friend number of the friend whose status message * changed. * @param message A byte array containing the same data as - * tox_friend_get_status_message would write to its `status_message` parameter. + * tox_friend_get_status_message would write to its `status_message` + * parameter. * @param length A value equal to the return value of * tox_friend_get_status_message_size. */ @@ -1814,7 +1890,8 @@ typedef uint32_t Tox_Friend_Message_Id; * then reassemble the fragments. Messages may not be empty. * * The return value of this function is the message ID. If a read receipt is - * received, the triggered `friend_read_receipt` event will be passed this message ID. + * received, the triggered `friend_read_receipt` event will be passed this + * message ID. * * Message IDs are unique per friend. The first message ID is 0. Message IDs are * incremented by 1 each time a message is sent. If UINT32_MAX messages were @@ -1831,7 +1908,8 @@ Tox_Friend_Message_Id tox_friend_send_message( const uint8_t message[], size_t length, Tox_Err_Friend_Send_Message *error); /** - * @param friend_number The friend number of the friend who received the message. + * @param friend_number The friend number of the friend who received the + * message. * @param message_id The message ID as returned from tox_friend_send_message * corresponding to the message sent. */ @@ -1875,6 +1953,7 @@ void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback); /** * @param friend_number The friend number of the friend who sent the message. + * @param type The type of the message (normal, action, ...). * @param message The message data they sent. * @param length The size of the message byte array. */ @@ -1906,10 +1985,10 @@ typedef uint32_t Tox_File_Number; * primarily for validating cached avatars. This use is highly recommended to * avoid unnecessary avatar updates. * - * If hash is NULL or data is NULL while length is not 0 the function returns false, - * otherwise it returns true. + * If hash is NULL or data is NULL while length is not 0 the function returns + * false, otherwise it returns true. * - * This function is a wrapper to events_alloc message-digest functions. + * This function is a wrapper to internal message-digest functions. * * @param hash A valid memory location the hash data. It must be at least * TOX_HASH_LENGTH bytes in size. @@ -1923,17 +2002,17 @@ bool tox_hash(uint8_t hash[TOX_HASH_LENGTH], const uint8_t data[], size_t length /** * @brief A list of pre-defined file kinds. * - * Toxcore itself does not behave differently for different file kinds. These - * are a hint to the client telling it what use the sender intended for the - * file. The `kind` parameter in the send function and recv callback are + * The Tox library itself does not behave differently for different file kinds. + * These are a hint to the client telling it what use the sender intended for + * the file. The `kind` parameter in the send function and recv callback are * `uint32_t`, not Tox_File_Kind, because clients can invent their own file * kind. Unknown file kinds should be treated as TOX_FILE_KIND_DATA. */ enum Tox_File_Kind { /** - * Arbitrary file data. Clients can choose to handle it based on the file name - * or magic or any other way they choose. + * Arbitrary file data. Clients can choose to handle it based on the file + * name or magic or any other way they choose. */ TOX_FILE_KIND_DATA, @@ -1941,21 +2020,21 @@ enum Tox_File_Kind { * Avatar file_id. This consists of tox_hash(image). * Avatar data. This consists of the image data. * - * Avatars can be sent at any time the client wishes. Generally, a client will - * send the avatar to a friend when that friend comes online, and to all - * friends when the avatar changed. A client can save some traffic by - * remembering which friend received the updated avatar already and only send - * it if the friend has an out of date avatar. + * Avatars can be sent at any time the client wishes. Generally, a client + * will send the avatar to a friend when that friend comes online, and to + * all friends when the avatar changed. A client can save some traffic by + * remembering which friend received the updated avatar already and only + * send it if the friend has an out of date avatar. * * Clients who receive avatar send requests can reject it (by sending * TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by - * sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH bytes - * (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client can compare - * this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar - * transfer if it matches. + * sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH + * bytes (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client + * can compare this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL + * to terminate the avatar transfer if it matches. * - * When file_size is set to 0 in the transfer request it means that the client - * has no avatar. + * When file_size is set to 0 in the transfer request it means that the + * client has no avatar. */ TOX_FILE_KIND_AVATAR, @@ -1964,16 +2043,17 @@ enum Tox_File_Kind { typedef enum Tox_File_Control { /** - * Sent by the receiving side to accept a file send request. Also sent after a - * TOX_FILE_CONTROL_PAUSE command to continue sending or receiving. + * Sent by the receiving side to accept a file send request. Also sent after + * a TOX_FILE_CONTROL_PAUSE command to continue sending or receiving. */ TOX_FILE_CONTROL_RESUME, /** * Sent by clients to pause the file transfer. The initial state of a file - * transfer is always paused on the receiving side and running on the sending - * side. If both the sending and receiving side pause the transfer, then both - * need to send TOX_FILE_CONTROL_RESUME for the transfer to resume. + * transfer is always paused on the receiving side and running on the + * sending side. If both the sending and receiving side pause the transfer, + * then both need to send TOX_FILE_CONTROL_RESUME for the transfer to + * resume. */ TOX_FILE_CONTROL_PAUSE, @@ -2005,7 +2085,8 @@ typedef enum Tox_Err_File_Control { TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED, /** - * No file transfer with the given file number was found for the given friend. + * No file transfer with the given file number was found for the given + * friend. */ TOX_ERR_FILE_CONTROL_NOT_FOUND, @@ -2089,7 +2170,8 @@ typedef enum Tox_Err_File_Seek { TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED, /** - * No file transfer with the given file number was found for the given friend. + * No file transfer with the given file number was found for the given + * friend. */ TOX_ERR_FILE_SEEK_NOT_FOUND, @@ -2113,7 +2195,8 @@ typedef enum Tox_Err_File_Seek { const char *tox_err_file_seek_to_string(Tox_Err_File_Seek value); /** - * @brief Sends a file seek control command to a friend for a given file transfer. + * @brief Sends a file seek control command to a friend for a given file + * transfer. * * This function can only be called to resume a file transfer right before * TOX_FILE_CONTROL_RESUME is sent. @@ -2144,7 +2227,8 @@ typedef enum Tox_Err_File_Get { TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, /** - * No file transfer with the given file number was found for the given friend. + * No file transfer with the given file number was found for the given + * friend. */ TOX_ERR_FILE_GET_NOT_FOUND, @@ -2158,8 +2242,8 @@ const char *tox_err_file_get_to_string(Tox_Err_File_Get value); * @param friend_number The friend number of the friend the file is being * transferred to or received from. * @param file_number The friend-specific identifier for the file transfer. - * @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If - * this parameter is NULL, this function has no effect. + * @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If this + * parameter is NULL, this function has no effect. * * @return true on success. */ @@ -2202,8 +2286,8 @@ typedef enum Tox_Err_File_Send { TOX_ERR_FILE_SEND_NAME_TOO_LONG, /** - * Too many ongoing transfers. The maximum number of concurrent file transfers - * is 256 per friend per direction (sending and receiving). + * Too many ongoing transfers. The maximum number of concurrent file + * transfers is 256 per friend per direction (sending and receiving). */ TOX_ERR_FILE_SEND_TOO_MANY, @@ -2214,8 +2298,8 @@ const char *tox_err_file_send_to_string(Tox_Err_File_Send value); /** * @brief Send a file transmission request. * - * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename - * should generally just be a file name, not a path with directory names. + * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename should + * generally just be a file name, not a path with directory names. * * If a non-UINT64_MAX file size is provided, it can be used by both sides to * determine the sending progress. File size can be set to UINT64_MAX for @@ -2224,8 +2308,8 @@ const char *tox_err_file_send_to_string(Tox_Err_File_Send value); * File transmission occurs in chunks, which are requested through the * `file_chunk_request` event. * - * When a friend goes offline, all file transfers associated with the friend are - * purged from core. + * When a friend goes offline, all file transfers associated with the friend get + * purged. * * If the file contents change during a transfer, the behaviour is unspecified * in general. What will actually happen depends on the mode in which the file @@ -2234,15 +2318,16 @@ const char *tox_err_file_send_to_string(Tox_Err_File_Send value); * - If the file size was increased * - and sending mode was streaming (file_size = UINT64_MAX), the behaviour * will be as expected. - * - and sending mode was file (file_size != UINT64_MAX), the file_chunk_request - * callback will receive length = 0 when Core thinks the file transfer has - * finished. If the client remembers the file size as it was when sending the - * request, it will terminate the transfer normally. If the client re-reads the - * size, it will think the friend cancelled the transfer. + * - and sending mode was file (file_size != UINT64_MAX), the + * file_chunk_request callback will receive length = 0 when Tox thinks the + * file transfer has finished. If the client remembers the file size as it + * was when sending the request, it will terminate the transfer normally. If + * the client re-reads the size, it will think the friend cancelled the + * transfer. * - If the file size was decreased * - and sending mode was streaming, the behaviour is as expected. * - and sending mode was file, the callback will return 0 at the new - * (earlier) end-of-file, signalling to the friend that the transfer was + * (earlier) end-of-file, signaling to the friend that the transfer was * cancelled. * - If the file contents were modified * - at a position before the current read, the two files (local and remote) @@ -2255,19 +2340,20 @@ const char *tox_err_file_send_to_string(Tox_Err_File_Send value); * @param friend_number The friend number of the friend the file send request * should be sent to. * @param kind The meaning of the file to be sent. - * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if - * unknown or streaming. - * @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be used to - * uniquely identify file transfers across core restarts. If NULL, a random one will - * be generated by core. It can then be obtained by using `tox_file_get_file_id()`. + * @param file_size Size in bytes of the file the client wants to send, + * UINT64_MAX if unknown or streaming. + * @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be + * used to uniquely identify file transfers across Tox restarts. If NULL, a + * random one will be generated by the library. It can then be obtained by + * using `tox_file_get_file_id()`. * @param filename Name of the file. Does not need to be the actual name. This * name will be sent along with the file send request. * @param filename_length Size in bytes of the filename. * * @return A file number used as an identifier in subsequent callbacks. This * number is per friend. File numbers are reused after a transfer terminates. - * On failure, this function returns an unspecified value. Any pattern in file numbers - * should not be relied on. + * On failure, this function returns an unspecified value. Any pattern in file + * numbers should not be relied on. */ Tox_File_Number tox_file_send( Tox *tox, Tox_Friend_Number friend_number, uint32_t kind, uint64_t file_size, @@ -2297,20 +2383,23 @@ typedef enum Tox_Err_File_Send_Chunk { TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED, /** - * No file transfer with the given file number was found for the given friend. + * No file transfer with the given file number was found for the given + * friend. */ TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND, /** * File transfer was found but isn't in a transferring state: (paused, done, - * broken, etc...) (happens only when not called from the request chunk callback). + * broken, etc...) (happens only when not called from the request chunk + * callback). */ TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING, /** - * Attempted to send more or less data than requested. The requested data size is - * adjusted according to maximum transmission unit and the expected end of - * the file. Trying to send less or more than requested will return this error. + * Attempted to send more or less data than requested. The requested data + * size is adjusted according to maximum transmission unit and the expected + * end of the file. Trying to send less or more than requested will return + * this error. */ TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH, @@ -2334,10 +2423,11 @@ const char *tox_err_file_send_chunk_to_string(Tox_Err_File_Send_Chunk value); * This function is called in response to the `file_chunk_request` callback. The * length parameter should be equal to the one received though the callback. * If it is zero, the transfer is assumed complete. For files with known size, - * Core will know that the transfer is complete after the last byte has been + * Tox will know that the transfer is complete after the last byte has been * received, so it is not necessary (though not harmful) to send a zero-length - * chunk to terminate. For streams, core will know that the transfer is finished - * if a chunk with length less than the length requested in the callback is sent. + * chunk to terminate. For streams, Tox will know that the transfer is finished + * if a chunk with length less than the length requested in the callback is + * sent. * * @param friend_number The friend number of the receiving friend for this file. * @param file_number The file transfer identifier returned by tox_file_send. @@ -2379,7 +2469,7 @@ typedef void tox_file_chunk_request_cb( * * Pass NULL to unset. * - * This event is triggered when Core is ready to send more file data. + * This event is triggered when Tox is ready to send more file data. */ void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback); @@ -2466,7 +2556,8 @@ typedef uint32_t Tox_Conference_Offline_Peer_Number; typedef enum Tox_Conference_Type { /** - * Text-only conferences that must be accepted with the tox_conference_join function. + * Text-only conferences that must be accepted with the tox_conference_join + * function. */ TOX_CONFERENCE_TYPE_TEXT, @@ -2503,7 +2594,8 @@ typedef void tox_conference_invite_cb( void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback); /** - * @param conference_number The conference number of the conference to which we have connected. + * @param conference_number The conference number of the conference to which we + * have connected. */ typedef void tox_conference_connected_cb(Tox *tox, Tox_Conference_Number conference_number, void *user_data); @@ -2556,7 +2648,8 @@ typedef void tox_conference_title_cb( * * This event is triggered when a peer changes the conference title. * - * If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference). + * If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining + * the conference). */ void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback); @@ -2641,7 +2734,8 @@ const char *tox_err_conference_delete_to_string(Tox_Err_Conference_Delete value) /** * @brief This function deletes a conference. * - * @param conference_number The conference number of the conference to be deleted. + * @param conference_number The conference number of the conference to be + * deleted. * * @return true on success. */ @@ -2698,7 +2792,8 @@ size_t tox_conference_peer_get_name_size( /** * @brief Copy the name of peer_number who is in conference_number to name. * - * Call tox_conference_peer_get_name_size to determine the allocation size for the `name` parameter. + * Call tox_conference_peer_get_name_size to determine the allocation size for + * the `name` parameter. * * @param name A valid memory region large enough to store the peer's name. * @@ -2709,7 +2804,8 @@ bool tox_conference_peer_get_name( uint8_t name[], Tox_Err_Conference_Peer_Query *error); /** - * @brief Copy the public key of peer_number who is in conference_number to public_key. + * @brief Copy the public key of peer_number who is in conference_number to + * public_key. * * public_key must be TOX_PUBLIC_KEY_SIZE long. * @@ -2748,7 +2844,8 @@ size_t tox_conference_offline_peer_get_name_size( Tox_Conference_Offline_Peer_Number offline_peer_number, Tox_Err_Conference_Peer_Query *error); /** - * @brief Copy the name of offline_peer_number who is in conference_number to name. + * @brief Copy the name of offline_peer_number who is in conference_number to + * name. * * Call tox_conference_offline_peer_get_name_size to determine the allocation * size for the `name` parameter. @@ -2762,7 +2859,8 @@ bool tox_conference_offline_peer_get_name( uint8_t name[], Tox_Err_Conference_Peer_Query *error); /** - * @brief Copy the public key of offline_peer_number who is in conference_number to public_key. + * @brief Copy the public key of offline_peer_number who is in conference_number + * to public_key. * * public_key must be TOX_PUBLIC_KEY_SIZE long. * @@ -2773,7 +2871,8 @@ bool tox_conference_offline_peer_get_public_key( Tox_Conference_Offline_Peer_Number offline_peer_number, uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Conference_Peer_Query *error); /** - * @brief Return a unix-time timestamp of the last time offline_peer_number was seen to be active. + * @brief Return a unix-time timestamp of the last time offline_peer_number was + * seen to be active. */ uint64_t tox_conference_offline_peer_get_last_active( const Tox *tox, Tox_Conference_Number conference_number, @@ -2832,7 +2931,8 @@ const char *tox_err_conference_invite_to_string(Tox_Err_Conference_Invite value) * @brief Invites a friend to a conference. * * @param friend_number The friend number of the friend we want to invite. - * @param conference_number The conference number of the conference we want to invite the friend to. + * @param conference_number The conference number of the conference we want to + * invite the friend to. * * @return true on success. */ @@ -2853,7 +2953,8 @@ typedef enum Tox_Err_Conference_Join { TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH, /** - * The conference is not the expected type. This indicates an invalid cookie. + * The conference is not the expected type. This indicates an invalid + * cookie. */ TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE, @@ -2877,6 +2978,11 @@ typedef enum Tox_Err_Conference_Join { */ TOX_ERR_CONFERENCE_JOIN_FAIL_SEND, + /** + * The cookie passed was NULL. + */ + TOX_ERR_CONFERENCE_JOIN_NULL, + } Tox_Err_Conference_Join; const char *tox_err_conference_join_to_string(Tox_Err_Conference_Join value); @@ -2888,7 +2994,7 @@ const char *tox_err_conference_join_to_string(Tox_Err_Conference_Join value); * to it until a handshaking procedure has been completed. A * `conference_connected` event will then occur for the conference. The client * will then remain connected to the conference until the conference is deleted, - * even across core restarts. Many operations on a conference will fail with a + * even across Tox restarts. Many operations on a conference will fail with a * corresponding error if attempted on a conference to which the client is not * yet connected. * @@ -2996,9 +3102,11 @@ size_t tox_conference_get_title_size( const Tox *tox, Tox_Conference_Number conference_number, Tox_Err_Conference_Title *error); /** - * @brief Write the title designated by the given conference number to a byte array. + * @brief Write the title designated by the given conference number to a byte + * array. * - * Call tox_conference_get_title_size to determine the allocation size for the `title` parameter. + * Call tox_conference_get_title_size to determine the allocation size for the + * `title` parameter. * * The data written to `title` is equal to the data received by the last * `conference_title` callback. @@ -3014,7 +3122,8 @@ bool tox_conference_get_title( Tox_Err_Conference_Title *error); /** - * @brief Set the conference title and broadcast it to the rest of the conference. + * @brief Set the conference title and broadcast it to the rest of the + * conference. * * Title length cannot be longer than TOX_MAX_NAME_LENGTH. * @@ -3028,7 +3137,8 @@ bool tox_conference_set_title( /** * @brief Return the number of conferences in the Tox instance. * - * This should be used to determine how much memory to allocate for `tox_conference_get_chatlist`. + * This should be used to determine how much memory to allocate for + * `tox_conference_get_chatlist`. */ size_t tox_conference_get_chatlist_size(const Tox *tox); @@ -3038,8 +3148,8 @@ size_t tox_conference_get_chatlist_size(const Tox *tox); * Determine how much space to allocate for the array with the * `tox_conference_get_chatlist_size` function. * - * Note that `tox_get_savedata` saves all connected conferences; - * when toxcore is created from savedata in which conferences were saved, those + * Note that `tox_get_savedata` saves all connected conferences; when a Tox + * instance is created from savedata in which conferences were saved, those * conferences will be connected at startup, and will be listed by * `tox_conference_get_chatlist`. * @@ -3049,7 +3159,8 @@ size_t tox_conference_get_chatlist_size(const Tox *tox); void tox_conference_get_chatlist(const Tox *tox, Tox_Conference_Number chatlist[]); /** - * @brief Returns the type of conference (Tox_Conference_Type) that conference_number is. + * @brief Returns the type of conference (Tox_Conference_Type) that + * conference_number is. * * Return value is unspecified on failure. */ @@ -3124,10 +3235,12 @@ Tox_Conference_Number tox_conference_by_id( * * If uid is NULL, this function has no effect. * - * @param uid A memory region large enough to store TOX_CONFERENCE_UID_SIZE bytes. + * @param uid A memory region large enough to store TOX_CONFERENCE_UID_SIZE + * bytes. * * @return true on success. - * @deprecated use tox_conference_get_id instead (exactly the same function, just renamed). + * @deprecated use tox_conference_get_id instead (exactly the same function, + * just renamed). */ bool tox_conference_get_uid( const Tox *tox, Tox_Conference_Number conference_number, uint8_t uid[TOX_CONFERENCE_UID_SIZE]); @@ -3156,10 +3269,12 @@ const char *tox_err_conference_by_uid_to_string(Tox_Err_Conference_By_Uid value) /** * @brief Return the conference number associated with the specified uid. * - * @param uid A byte array containing the conference id (TOX_CONFERENCE_UID_SIZE). + * @param uid A byte array containing the conference id + * (TOX_CONFERENCE_UID_SIZE). * * @return the conference number on success, an unspecified value on failure. - * @deprecated use tox_conference_by_id instead (exactly the same function, just renamed). + * @deprecated use tox_conference_by_id instead (exactly the same function, + * just renamed). */ Tox_Conference_Number tox_conference_by_uid( const Tox *tox, const uint8_t uid[TOX_CONFERENCE_UID_SIZE], Tox_Err_Conference_By_Uid *error); @@ -3193,8 +3308,9 @@ typedef enum Tox_Err_Friend_Custom_Packet { TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED, /** - * The first byte of data was not in the specified range for the packet type. - * This range is 192-254 for lossy, and 69, 160-191 for lossless packets. + * The first byte of data was not one of the permitted values; + * for lossy packets the first byte must be in the range 192-254, + * and for lossless packets it must be either 69 or in the range 160-191. */ TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID, @@ -3245,7 +3361,7 @@ bool tox_friend_send_lossy_packet( /** * @brief Send a custom lossless packet to a friend. * - * The first byte of data must be in the range 69, 160-191. Maximum length of a + * The first byte of data must be either 69 or in the range 160-191. Maximum length of a * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE. * * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) @@ -3264,6 +3380,9 @@ bool tox_friend_send_lossless_packet( Tox_Err_Friend_Custom_Packet *error); /** + * tox_callback_friend_lossy_packet is the compatibility function to + * set the callback for all packet IDs except those reserved for ToxAV. + * * @param friend_number The friend number of the friend who sent a lossy packet. * @param data A byte array containing the received packet data. * @param length The length of the packet data byte array. @@ -3323,7 +3442,8 @@ const char *tox_err_get_port_to_string(Tox_Err_Get_Port value); * @brief Writes the temporary DHT public key of this instance to a byte array. * * This can be used in combination with an externally accessible IP address and - * the bound port (from tox_self_get_udp_port) to run a temporary bootstrap node. + * the bound port (from tox_self_get_udp_port) to run a temporary bootstrap + * node. * * Be aware that every time a new instance is created, the DHT public key * changes, meaning this cannot be used to run a permanent bootstrap node. @@ -3436,22 +3556,24 @@ uint32_t tox_group_peer_public_key_size(void); typedef enum Tox_Group_Privacy_State { /** - * The group is considered to be public. Anyone may join the group using the Chat ID. + * The group is considered to be public. Anyone may join the group using + * the Chat ID. * - * If the group is in this state, even if the Chat ID is never explicitly shared - * with someone outside of the group, information including the Chat ID, IP addresses, - * and peer ID's (but not Tox ID's) is visible to anyone with access to a node - * storing a DHT entry for the given group. + * If the group is in this state, even if the Chat ID is never explicitly + * shared with someone outside of the group, information including the Chat + * ID, IP addresses, and peer ID's (but not Tox ID's) is visible to anyone + * with access to a node storing a DHT entry for the given group. */ TOX_GROUP_PRIVACY_STATE_PUBLIC, /** - * The group is considered to be private. The only way to join the group is by having - * someone in your contact list send you an invite. + * The group is considered to be private. The only way to join the group is + * by having someone in your contact list send you an invite. * - * If the group is in this state, no group information (mentioned above) is present in the DHT; - * the DHT is not used for any purpose at all. If a public group is set to private, - * all DHT information related to the group will expire shortly. + * If the group is in this state, no group information (mentioned above) is + * present in the DHT; the DHT is not used for any purpose at all. If a + * public group is set to private, all DHT information related to the group + * will expire shortly. */ TOX_GROUP_PRIVACY_STATE_PRIVATE, @@ -3461,16 +3583,20 @@ const char *tox_group_privacy_state_to_string(Tox_Group_Privacy_State value); /** * Represents the state of the group topic lock. + * + * The default is enabled. */ typedef enum Tox_Group_Topic_Lock { /** - * The topic lock is enabled. Only peers with the founder and moderator roles may set the topic. + * The topic lock is enabled. Only peers with the founder and moderator + * roles may set the topic. */ TOX_GROUP_TOPIC_LOCK_ENABLED, /** - * The topic lock is disabled. All peers except those with the observer role may set the topic. + * The topic lock is disabled. All peers except those with the observer role + * may set the topic. */ TOX_GROUP_TOPIC_LOCK_DISABLED, @@ -3479,8 +3605,9 @@ typedef enum Tox_Group_Topic_Lock { const char *tox_group_topic_lock_to_string(Tox_Group_Topic_Lock value); /** - * Represents the group voice state, which determines which Group Roles have permission to speak - * in the group chat. The voice state does not have any effect private messages or topic setting. + * Represents the group voice state, which determines which Group Roles have + * permission to speak in the group chat. The voice state does not have any + * effect private messages or topic setting. */ typedef enum Tox_Group_Voice_State { /** @@ -3504,14 +3631,15 @@ const char *tox_group_voice_state_to_string(Tox_Group_Voice_State value); /** * Represents group roles. * - * Roles are hierarchical in that each role has a set of privileges plus all the privileges - * of the roles below it. + * Roles are hierarchical in that each role has a set of privileges plus all the + * privileges of the roles below it. */ typedef enum Tox_Group_Role { /** - * May kick all other peers as well as set their role to anything (except founder). - * Founders may also set the group password, toggle the privacy state, and set the peer limit. + * May kick all other peers as well as set their role to anything (except + * founder). Founders may also set the group password, toggle the privacy + * state, and set the peer limit. */ TOX_GROUP_ROLE_FOUNDER, @@ -3527,7 +3655,8 @@ typedef enum Tox_Group_Role { TOX_GROUP_ROLE_USER, /** - * May observe the group and ignore peers; may not communicate with other peers or with the group. + * May observe the group and ignore peers; may not communicate with other + * peers or with the group. */ TOX_GROUP_ROLE_OBSERVER, @@ -3549,7 +3678,8 @@ typedef enum Tox_Err_Group_New { TOX_ERR_GROUP_NEW_OK, /** - * name exceeds TOX_MAX_NAME_LENGTH or group_name exceeded TOX_GROUP_MAX_GROUP_NAME_LENGTH. + * name exceeds TOX_MAX_NAME_LENGTH or group_name exceeded + * TOX_GROUP_MAX_GROUP_NAME_LENGTH. */ TOX_ERR_GROUP_NEW_TOO_LONG, @@ -3564,13 +3694,14 @@ typedef enum Tox_Err_Group_New { TOX_ERR_GROUP_NEW_INIT, /** - * The group state failed to initialize. This usually indicates that something went wrong - * related to cryptographic signing. + * The group state failed to initialize. This usually indicates that + * something went wrong related to cryptographic signing. */ TOX_ERR_GROUP_NEW_STATE, /** - * The group failed to announce to the DHT. This indicates a network related error. + * The group failed to announce to the DHT. This indicates a network related + * error. */ TOX_ERR_GROUP_NEW_ANNOUNCE, @@ -3585,18 +3716,19 @@ const char *tox_err_group_new_to_string(Tox_Err_Group_New value); * * The caller of this function has Founder role privileges. * - * The client should initiate its peer list with self info after calling this function, as - * the peer_join callback will not be triggered. + * The client should initiate its peer list with self info after calling this + * function, as the peer_join callback will not be triggered. * - * @param privacy_state The privacy state of the group. If this is set to TOX_GROUP_PRIVACY_STATE_PUBLIC, - * the group will attempt to announce itself to the DHT and anyone with the Chat ID may join. - * Otherwise a friend invite will be required to join the group. + * @param privacy_state The privacy state of the group. If this is set to + * TOX_GROUP_PRIVACY_STATE_PUBLIC, the group will attempt to announce itself + * to the DHT and anyone with the Chat ID may join. Otherwise a friend invite + * will be required to join the group. * @param group_name The name of the group. The name must be non-NULL. - * @param group_name_length The length of the group name. This must be greater than zero and no larger than - * TOX_GROUP_MAX_GROUP_NAME_LENGTH. + * @param group_name_length The length of the group name. This must be greater + * than zero and no larger than TOX_GROUP_MAX_GROUP_NAME_LENGTH. * @param name The name of the peer creating the group. - * @param name_length The length of the peer's name. This must be greater than zero and no larger - * than TOX_MAX_NAME_LENGTH. + * @param name_length The length of the peer's name. This must be greater than + * zero and no larger than TOX_MAX_NAME_LENGTH. * * @return group_number on success, UINT32_MAX on failure. */ @@ -3618,8 +3750,9 @@ typedef enum Tox_Err_Group_Join { TOX_ERR_GROUP_JOIN_INIT, /** - * The chat_id pointer is set to NULL or a group with chat_id already exists. This usually - * happens if the client attempts to create multiple sessions for the same group. + * The chat_id pointer is set to NULL or a group with chat_id already + * exists. This usually happens if the client attempts to create multiple + * sessions for the same group. */ TOX_ERR_GROUP_JOIN_BAD_CHAT_ID, @@ -3634,7 +3767,8 @@ typedef enum Tox_Err_Group_Join { TOX_ERR_GROUP_JOIN_TOO_LONG, /** - * Failed to set password. This usually occurs if the password exceeds TOX_GROUP_MAX_PASSWORD_SIZE. + * Failed to set password. This usually occurs if the password exceeds + * TOX_GROUP_MAX_PASSWORD_SIZE. */ TOX_ERR_GROUP_JOIN_PASSWORD, @@ -3648,19 +3782,25 @@ typedef enum Tox_Err_Group_Join { const char *tox_err_group_join_to_string(Tox_Err_Group_Join value); /** - * Joins a group chat with specified Chat ID. + * Joins a group chat with specified Chat ID or reconnects to an existing group. + * + * This function creates a new group chat object, adds it to the chats array, + * and sends a DHT announcement to find peers in the group associated with + * chat_id. Once a peer has been found a join attempt will be initiated. * - * This function creates a new group chat object, adds it to the chats array, and sends - * a DHT announcement to find peers in the group associated with chat_id. Once a peer has been - * found a join attempt will be initiated. + * If a group with the specified Chat ID already exists, this function will attempt + * to reconnect to the group. * - * @param chat_id The Chat ID of the group you wish to join. This must be TOX_GROUP_CHAT_ID_SIZE bytes. - * @param password The password required to join the group. Set to NULL if no password is required. - * @param password_length The length of the password. If length is equal to zero, - * the password parameter is ignored. length must be no larger than TOX_GROUP_MAX_PASSWORD_SIZE. + * @param chat_id The Chat ID of the group you wish to join. This must be + * TOX_GROUP_CHAT_ID_SIZE bytes. + * @param password The password required to join the group. Set to NULL if no + * password is required. + * @param password_length The length of the password. If length is equal to + * zero, the password parameter is ignored. length must be no larger than + * TOX_GROUP_MAX_PASSWORD_SIZE. * @param name The name of the peer joining the group. - * @param name_length The length of the peer's name. This must be greater than zero and no larger - * than TOX_MAX_NAME_LENGTH. + * @param name_length The length of the peer's name. This must be greater than + * zero and no larger than TOX_MAX_NAME_LENGTH. * * @return group_number on success, UINT32_MAX on failure. */ @@ -3687,8 +3827,8 @@ typedef enum Tox_Err_Group_Is_Connected { const char *tox_err_group_is_connected_to_string(Tox_Err_Group_Is_Connected value); /** - * Returns true if the group chat is currently connected or attempting to connect to other peers - * in the group. + * Returns true if the group chat is currently connected or attempting to + * connect to other peers in the group. * * @param group_number The group number of the designated group. */ @@ -3715,7 +3855,8 @@ typedef enum Tox_Err_Group_Disconnect { const char *tox_err_group_disconnect_to_string(Tox_Err_Group_Disconnect value); /** - * Disconnects from a group chat while retaining the group state and credentials. + * Disconnects from a group chat while retaining the group state and + * credentials. * * Returns true if we successfully disconnect from the group. * @@ -3747,12 +3888,15 @@ const char *tox_err_group_reconnect_to_string(Tox_Err_Group_Reconnect value); /** * Reconnects to a group. * - * This function disconnects from all peers in the group, then attempts to reconnect with the group. - * The caller's state is not changed (i.e. name, status, role, chat public key etc.). + * This function disconnects from all peers in the group, then attempts to + * reconnect with the group. The caller's state is not changed (i.e. name, + * status, role, chat public key etc.). * * @param group_number The group number of the group we wish to reconnect to. * * @return true on success. + * + * @deprecated Use `tox_group_join` instead. */ bool tox_group_reconnect(Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_Reconnect *error); @@ -3784,14 +3928,16 @@ const char *tox_err_group_leave_to_string(Tox_Err_Group_Leave value); /** * Leaves a group. * - * This function sends a parting packet containing a custom (non-obligatory) message to all - * peers in a group, and deletes the group from the chat array. All group state information is permanently - * lost, including keys and role credentials. + * This function sends a parting packet containing a custom (non-obligatory) + * message to all peers in a group, and deletes the group from the chat array. + * All group state information is permanently lost, including keys and role + * credentials. * * @param group_number The group number of the group we wish to leave. - * @param part_message The parting message to be sent to all the peers. Set to NULL if we do not wish to - * send a parting message. - * @param length The length of the parting message. Set to 0 if we do not wish to send a parting message. + * @param part_message The parting message to be sent to all the peers. Set to + * NULL if we do not wish to send a parting message. + * @param length The length of the parting message. Set to 0 if we do not wish + * to send a parting message. * * @return true if the group chat instance is successfully deleted. */ @@ -3860,10 +4006,11 @@ typedef enum Tox_Err_Group_Self_Name_Set { const char *tox_err_group_self_name_set_to_string(Tox_Err_Group_Self_Name_Set value); /** - * Set the client's nickname for the group instance designated by the given group number. + * Set the client's nickname for the group instance designated by the given + * group number. * - * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is equal to zero or name is a NULL - * pointer, the function call will fail. + * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is equal to + * zero or name is a NULL pointer, the function call will fail. * * @param name A byte array containing the new nickname. * @param length The size of the name byte array. @@ -3876,8 +4023,8 @@ bool tox_group_self_set_name( Tox_Err_Group_Self_Name_Set *error); /** - * Return the length of the client's current nickname for the group instance designated - * by group_number as passed to tox_group_self_set_name. + * Return the length of the client's current nickname for the group instance + * designated by group_number as passed to tox_group_self_set_name. * * If no nickname was set before calling this function, the name is empty, * and this function returns 0. @@ -3892,7 +4039,8 @@ size_t tox_group_self_get_name_size(const Tox *tox, Tox_Group_Number group_numbe * If no nickname was set before calling this function, the name is empty, * and this function has no effect. * - * Call tox_group_self_get_name_size to find out how much memory to allocate for the result. + * Call tox_group_self_get_name_size to find out how much memory to allocate for + * the result. * * @param name A valid memory location large enough to hold the nickname. * If this parameter is NULL, the function has no effect. @@ -3928,7 +4076,8 @@ typedef enum Tox_Err_Group_Self_Status_Set { const char *tox_err_group_self_status_set_to_string(Tox_Err_Group_Self_Status_Set value); /** - * Set the client's status for the group instance. Status must be a Tox_User_Status. + * Set the client's status for the group instance. Status must be a + * Tox_User_Status. * * @return true on success. */ @@ -3954,13 +4103,16 @@ Tox_Group_Role tox_group_self_get_role(const Tox *tox, Tox_Group_Number group_nu Tox_Group_Peer_Number tox_group_self_get_peer_id(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_Self_Query *error); /** - * Write the client's group public key designated by the given group number to a byte array. + * Write the client's group public key designated by the given group number to + * a byte array. * - * This key will be permanently tied to the client's identity for this particular group until - * the client explicitly leaves the group. This key is the only way for other peers to reliably - * identify the client across client restarts. + * This key will be permanently tied to the client's identity for this + * particular group until the client explicitly leaves the group. This key is + * the only way for other peers to reliably identify the client across client + * restarts. * - * `public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE bytes. + * `public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE + * bytes. * * @param public_key A valid memory region large enough to store the public key. * If this parameter is NULL, this function call has no effect. @@ -4001,8 +4153,8 @@ typedef enum Tox_Err_Group_Peer_Query { const char *tox_err_group_peer_query_to_string(Tox_Err_Group_Peer_Query value); /** - * Return the length of the peer's name. If the group number or ID is invalid, the - * return value is unspecified. + * Return the length of the peer's name. If the group number or ID is invalid, + * the return value is unspecified. * * @param group_number The group number of the group we wish to query. * @param peer_id The ID of the peer whose name length we want to retrieve. @@ -4017,7 +4169,8 @@ size_t tox_group_peer_get_name_size(const Tox *tox, Tox_Group_Number group_numbe * Write the name of the peer designated by the given ID to a byte * array. * - * Call tox_group_peer_get_name_size to determine the allocation size for the `name` parameter. + * Call tox_group_peer_get_name_size to determine the allocation size for the + * `name` parameter. * * The data written to `name` is equal to the data received by the last * `group_peer_name` callback. @@ -4046,8 +4199,8 @@ Tox_User_Status tox_group_peer_get_status(const Tox *tox, Tox_Group_Number group Tox_Err_Group_Peer_Query *error); /** - * Return the peer's role (user/moderator/founder...). If the ID or group number is - * invalid, the return value is unspecified. + * Return the peer's role (user/moderator/founder...). If the ID or group number + * is invalid, the return value is unspecified. * * @param group_number The group number of the group we wish to query. * @param peer_id The ID of the peer whose role we wish to query. @@ -4061,8 +4214,9 @@ Tox_Group_Role tox_group_peer_get_role(const Tox *tox, Tox_Group_Number group_nu /** * Return the type of connection we have established with a peer. * - * If `peer_id` designates ourself, the return value indicates whether we're capable - * of making UDP connections with other peers, or are limited to TCP connections. + * If `peer_id` designates ourself, the return value indicates whether we're + * capable of making UDP connections with other peers, or are limited to TCP + * connections. * * @param group_number The group number of the group we wish to query. * @param peer_id The ID of the peer whose connection status we wish to query. @@ -4071,13 +4225,15 @@ Tox_Connection tox_group_peer_get_connection_status(const Tox *tox, Tox_Group_Nu Tox_Err_Group_Peer_Query *error); /** - * Write the group public key with the designated peer_id for the designated group number to public_key. + * Write the group public key with the designated peer_id for the designated + * group number to public_key. * - * This key will be permanently tied to a particular peer until they explicitly leave the group and is - * the only way to reliably identify the same peer across client restarts. + * This key will be permanently tied to a particular peer until they explicitly + * leave the group and is the only way to reliably identify the same peer across + * client restarts. * - * `public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE bytes. If `public_key` is null - * this function has no effect. + * `public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE + * bytes. If `public_key` is NULL this function has no effect. * * @param group_number The group number of the group we wish to query. * @param peer_id The ID of the peer whose public key we wish to retrieve. @@ -4091,14 +4247,15 @@ bool tox_group_peer_get_public_key( uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Group_Peer_Query *error); /** - * @param group_number The group number of the group the name change is intended for. + * @param group_number The group number of the group the name change is intended + * for. * @param peer_id The ID of the peer who has changed their name. * @param name The name data. - * @param length The length of the name. + * @param name_length The length of the name. */ typedef void tox_group_peer_name_cb( Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, - const uint8_t name[], size_t length, void *user_data); + const uint8_t name[], size_t name_length, void *user_data); /** * Set the callback for the `group_peer_name` event. Pass NULL to unset. @@ -4108,7 +4265,8 @@ typedef void tox_group_peer_name_cb( void tox_callback_group_peer_name(Tox *tox, tox_group_peer_name_cb *callback); /** - * @param group_number The group number of the group the status change is intended for. + * @param group_number The group number of the group the status change is + * intended for. * @param peer_id The ID of the peer who has changed their status. * @param status The new status of the peer. */ @@ -4173,7 +4331,8 @@ typedef enum Tox_Err_Group_Topic_Set { TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS, /** - * The packet could not be created. This error is usually related to cryptographic signing. + * The packet could not be created. This error is usually related to + * cryptographic signing. */ TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE, @@ -4194,8 +4353,8 @@ const char *tox_err_group_topic_set_to_string(Tox_Err_Group_Topic_Set value); /** * Set the group topic and broadcast it to the rest of the group. * - * topic length cannot be longer than TOX_GROUP_MAX_TOPIC_LENGTH. If length is equal to zero or - * topic is set to NULL, the topic will be unset. + * Topic length cannot be longer than TOX_GROUP_MAX_TOPIC_LENGTH. If the length + * is equal to zero or topic is set to NULL, the topic will be unset. * * @return true on success. */ @@ -4216,7 +4375,8 @@ size_t tox_group_get_topic_size(const Tox *tox, Tox_Group_Number group_number, T /** * Write the topic designated by the given group number to a byte array. * - * Call tox_group_get_topic_size to determine the allocation size for the `topic` parameter. + * Call tox_group_get_topic_size to determine the allocation size for the + * `topic` parameter. * * The data written to `topic` is equal to the data received by the last * `group_topic` callback. @@ -4231,15 +4391,16 @@ bool tox_group_get_topic( uint8_t topic[], Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group the topic change is intended for. - * @param peer_id The ID of the peer who changed the topic. If the peer who set the topic - * is not present in our peer list this value will be set to 0. + * @param group_number The group number of the group the topic change is + * intended for. + * @param peer_id The ID of the peer who changed the topic. If the peer who set + * the topic is not present in our peer list this value will be set to 0. * @param topic The topic data. - * @param length The topic length. + * @param topic_length The topic length. */ typedef void tox_group_topic_cb( Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, - const uint8_t topic[], size_t length, + const uint8_t topic[], size_t topic_length, void *user_data); /** @@ -4256,9 +4417,11 @@ void tox_callback_group_topic(Tox *tox, tox_group_topic_cb *callback); size_t tox_group_get_name_size(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * Write the name of the group designated by the given group number to a byte array. + * Write the name of the group designated by the given group number to a byte + * array. * - * Call tox_group_get_name_size to determine the allocation size for the `name` parameter. + * Call tox_group_get_name_size to determine the allocation size for the `name` + * parameter. * * @param name A valid memory region large enough to store the group name. * If this parameter is NULL, this function call has no effect. @@ -4289,19 +4452,21 @@ bool tox_group_get_chat_id( uint32_t tox_group_get_number_groups(const Tox *tox); /** - * Return the privacy state of the group designated by the given group number. If group number - * is invalid, the return value is unspecified. + * Return the privacy state of the group designated by the given group number. + * If group number is invalid, the return value is unspecified. * * The value returned is equal to the data received by the last * `group_privacy_state` callback. * - * @see the `Group chat founder controls` section for the respective set function. + * @see the `Group chat Founder controls` section for the respective set + * function. */ Tox_Group_Privacy_State tox_group_get_privacy_state(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group the privacy state is intended for. + * @param group_number The group number of the group the privacy state is + * intended for. * @param privacy_state The new privacy state. */ typedef void tox_group_privacy_state_cb(Tox *tox, Tox_Group_Number group_number, Tox_Group_Privacy_State privacy_state, @@ -4315,18 +4480,21 @@ typedef void tox_group_privacy_state_cb(Tox *tox, Tox_Group_Number group_number, void tox_callback_group_privacy_state(Tox *tox, tox_group_privacy_state_cb *callback); /** - * Return the voice state of the group designated by the given group number. If group number - * is invalid, the return value is unspecified. + * Return the voice state of the group designated by the given group number. If + * group number is invalid, the return value is unspecified. * - * The value returned is equal to the data received by the last `group_voice_state` callback. + * The value returned is equal to the data received by the last + * `group_voice_state` callback. * - * @see the `Group chat founder controls` section for the respective set function. + * @see the `Group chat Founder controls` section for the respective set + * function. */ Tox_Group_Voice_State tox_group_get_voice_state(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group the voice state change is intended for. + * @param group_number The group number of the group the voice state change is + * intended for. * @param voice_state The new voice state. */ typedef void tox_group_voice_state_cb(Tox *tox, Tox_Group_Number group_number, Tox_Group_Voice_State voice_state, @@ -4340,19 +4508,22 @@ typedef void tox_group_voice_state_cb(Tox *tox, Tox_Group_Number group_number, T void tox_callback_group_voice_state(Tox *tox, tox_group_voice_state_cb *callback); /** - * Return the topic lock status of the group designated by the given group number. If group number + * Return the topic lock status of the group designated by the given group + * number. If group number * is invalid, the return value is unspecified. * * The value returned is equal to the data received by the last * `group_topic_lock` callback. * - * @see the `Group chat founder contols` section for the respective set function. + * @see the `Group chat Founder controls` section for the respective set + * function. */ Tox_Group_Topic_Lock tox_group_get_topic_lock(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group for which the topic lock has changed. + * @param group_number The group number of the group for which the topic lock + * has changed. * @param topic_lock The new topic lock state. */ typedef void tox_group_topic_lock_cb(Tox *tox, Tox_Group_Number group_number, Tox_Group_Topic_Lock topic_lock, void *user_data); @@ -4365,18 +4536,21 @@ typedef void tox_group_topic_lock_cb(Tox *tox, Tox_Group_Number group_number, To void tox_callback_group_topic_lock(Tox *tox, tox_group_topic_lock_cb *callback); /** - * Return the maximum number of peers allowed for the group designated by the given group number. - * If the group number is invalid, the return value is unspecified. + * Return the maximum number of peers allowed for the group designated by the + * given group number. If the group number is invalid, the return value is + * unspecified. * * The value returned is equal to the data received by the last * `group_peer_limit` callback. * - * @see the `Group chat founder controls` section for the respective set function. + * @see the `Group chat Founder controls` section for the respective set + * function. */ uint16_t tox_group_get_peer_limit(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group for which the peer limit has changed. + * @param group_number The group number of the group for which the peer limit + * has changed. * @param peer_limit The new peer limit for the group. */ typedef void tox_group_peer_limit_cb(Tox *tox, Tox_Group_Number group_number, uint32_t peer_limit, void *user_data); @@ -4384,7 +4558,8 @@ typedef void tox_group_peer_limit_cb(Tox *tox, Tox_Group_Number group_number, ui /** * Set the callback for the `group_peer_limit` event. Pass NULL to unset. * - * This event is triggered when the group founder changes the maximum peer limit. + * This event is triggered when the group founder changes the maximum peer + * limit. */ void tox_callback_group_peer_limit(Tox *tox, tox_group_peer_limit_cb *callback); @@ -4395,17 +4570,20 @@ void tox_callback_group_peer_limit(Tox *tox, tox_group_peer_limit_cb *callback); size_t tox_group_get_password_size(const Tox *tox, Tox_Group_Number group_number, Tox_Err_Group_State_Query *error); /** - * Write the password for the group designated by the given group number to a byte array. + * Write the password for the group designated by the given group number to a + * byte array. * - * Call tox_group_get_password_size to determine the allocation size for the `password` parameter. + * Call tox_group_get_password_size to determine the allocation size for the + * `password` parameter. * - * The data received is equal to the data received by the last - * `group_password` callback. + * The data received is equal to the data received by the last `group_password` + * callback. * - * @see the `Group chat Founder controls` section for the respective set function. + * @see the `Group chat Founder controls` section for the respective set + * function. * - * @param password A valid memory region large enough to store the group password. - * If this parameter is NULL, this function call has no effect. + * @param password A valid memory region large enough to store the group + * password. If this parameter is NULL, this function call has no effect. * * @return true on success. */ @@ -4414,13 +4592,14 @@ bool tox_group_get_password( Tox_Err_Group_State_Query *error); /** - * @param group_number The group number of the group for which the password has changed. + * @param group_number The group number of the group for which the password has + * changed. * @param password The new group password. - * @param length The length of the password. + * @param password_length The length of the password. */ typedef void tox_group_password_cb( Tox *tox, Tox_Group_Number group_number, - const uint8_t password[], size_t length, + const uint8_t password[], size_t password_length, void *user_data); /** @@ -4454,7 +4633,7 @@ typedef enum Tox_Err_Group_Send_Message { TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG, /** - * The message pointer is null or length is zero. + * The message pointer is NULL or length is zero. */ TOX_ERR_GROUP_SEND_MESSAGE_EMPTY, @@ -4488,12 +4667,13 @@ const char *tox_err_group_send_message_to_string(Tox_Err_Group_Send_Message valu * This function creates a group message packet and pushes it into the send * queue. * - * The message length may not exceed TOX_GROUP_MAX_MESSAGE_LENGTH. Larger messages - * must be split by the client and sent as separate messages. Other clients can - * then reassemble the fragments. Messages may not be empty. + * The message length may not exceed TOX_GROUP_MAX_MESSAGE_LENGTH. Larger + * messages must be split by the client and sent as separate messages. Other + * clients can then reassemble the fragments. Messages may not be empty. * - * @param group_number The group number of the group the message is intended for. - * @param type Message type (normal, action, ...). + * @param group_number The group number of the group the message is intended + * for. + * @param message_type Message type (normal, action, ...). * @param message A non-NULL pointer to the first element of a byte array * containing the message text. * @param length Length of the message to be sent. @@ -4502,7 +4682,7 @@ const char *tox_err_group_send_message_to_string(Tox_Err_Group_Send_Message valu * returned message ID value will be undefined. */ Tox_Group_Message_Id tox_group_send_message( - const Tox *tox, Tox_Group_Number group_number, Tox_Message_Type type, + const Tox *tox, Tox_Group_Number group_number, Tox_Message_Type message_type, const uint8_t message[], size_t length, Tox_Err_Group_Send_Message *error); @@ -4529,10 +4709,15 @@ typedef enum Tox_Err_Group_Send_Private_Message { TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG, /** - * The message pointer is null or length is zero. + * The message pointer is NULL or length is zero. */ TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY, + /** + * The message type is invalid. + */ + TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE, + /** * The caller does not have the required permissions to send group messages. */ @@ -4548,11 +4733,6 @@ typedef enum Tox_Err_Group_Send_Private_Message { */ TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED, - /** - * The message type is invalid. - */ - TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE, - } Tox_Err_Group_Send_Private_Message; const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Private_Message value); @@ -4560,15 +4740,17 @@ const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Priv /** * Send a text chat message to the specified peer in the specified group. * - * This function creates a group private message packet and pushes it into the send - * queue. + * This function creates a group private message packet and pushes it into the + * send queue. * - * The message length may not exceed TOX_GROUP_MAX_MESSAGE_LENGTH. Larger messages - * must be split by the client and sent as separate messages. Other clients can - * then reassemble the fragments. Messages may not be empty. + * The message length may not exceed TOX_GROUP_MAX_MESSAGE_LENGTH. Larger + * messages must be split by the client and sent as separate messages. Other + * clients can then reassemble the fragments. Messages may not be empty. * - * @param group_number The group number of the group the message is intended for. + * @param group_number The group number of the group the message is intended + * for. * @param peer_id The ID of the peer the message is intended for. + * @param message_type The type of message (normal, action, ...). * @param message A non-NULL pointer to the first element of a byte array * containing the message text. * @param length Length of the message to be sent. @@ -4576,7 +4758,7 @@ const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Priv * @return true on success. */ Tox_Group_Message_Id tox_group_send_private_message( - const Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type type, + const Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type message_type, const uint8_t message[], size_t length, Tox_Err_Group_Send_Private_Message *error); @@ -4600,7 +4782,7 @@ typedef enum Tox_Err_Group_Send_Custom_Packet { TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG, /** - * The message pointer is null or length is zero. + * The message pointer is NULL or length is zero. */ TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY, @@ -4622,15 +4804,17 @@ const char *tox_err_group_send_custom_packet_to_string(Tox_Err_Group_Send_Custom /** * Send a custom packet to the group. * - * If lossless is true the packet will be lossless. Lossless packet behaviour is comparable - * to TCP (reliability, arrive in order) but with packets instead of a stream. + * If lossless is true the packet will be lossless. Lossless packet behaviour is + * comparable to TCP (reliability, arrive in order) but with packets instead of + * a stream. * - * If lossless is false, the packet will be lossy. Lossy packets behave like UDP packets, - * meaning they might never reach the other side or might arrive more than once (if someone - * is messing with the connection) or might arrive in the wrong order. + * If lossless is false, the packet will be lossy. Lossy packets behave like UDP + * packets, meaning they might never reach the other side or might arrive more + * than once (if someone is messing with the connection) or might arrive in the + * wrong order. * - * Unless latency is an issue or message reliability is not important, it is recommended that you use - * lossless packets. + * Unless latency is an issue or message reliability is not important, it is + * recommended that you use lossless packets. * * The message length may not exceed TOX_MAX_CUSTOM_PACKET_SIZE. Larger packets * must be split by the client and sent as separate packets. Other clients can @@ -4668,7 +4852,7 @@ typedef enum Tox_Err_Group_Send_Custom_Private_Packet { TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_TOO_LONG, /** - * The message pointer is null or length is zero. + * The message pointer is NULL or length is zero. */ TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_EMPTY, @@ -4694,15 +4878,17 @@ const char *tox_err_group_send_custom_private_packet_to_string(Tox_Err_Group_Sen /** * Send a custom private packet to a designated peer in the group. * - * If lossless is true the packet will be lossless. Lossless packet behaviour is comparable - * to TCP (reliability, arrive in order) but with packets instead of a stream. + * If lossless is true the packet will be lossless. Lossless packet behaviour is + * comparable to TCP (reliability, arrive in order) but with packets instead of + * a stream. * - * If lossless is false, the packet will be lossy. Lossy packets behave like UDP packets, - * meaning they might never reach the other side or might arrive more than once (if someone - * is messing with the connection) or might arrive in the wrong order. + * If lossless is false, the packet will be lossy. Lossy packets behave like UDP + * packets, meaning they might never reach the other side or might arrive more + * than once (if someone is messing with the connection) or might arrive in the + * wrong order. * - * Unless latency is an issue or message reliability is not important, it is recommended that you use - * lossless packets. + * Unless latency is an issue or message reliability is not important, it is + * recommended that you use lossless packets. * * The packet length may not exceed TOX_MAX_CUSTOM_PACKET_SIZE. Larger packets * must be split by the client and sent as separate packets. Other clients can @@ -4727,16 +4913,18 @@ bool tox_group_send_custom_private_packet(const Tox *tox, Tox_Group_Number group ******************************************************************************/ /** - * @param group_number The group number of the group the message is intended for. + * @param group_number The group number of the group the message is intended + * for. * @param peer_id The ID of the peer who sent the message. - * @param type The type of message (normal, action, ...). + * @param message_type The type of message (normal, action, ...). * @param message The message data. - * @param message_id A pseudo message id that clients can use to uniquely identify this group message. - * @param length The length of the message. + * @param message_length The length of the message. + * @param message_id A pseudo message id that clients can use to uniquely + * identify this group message. */ typedef void tox_group_message_cb( - Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type type, - const uint8_t message[], size_t length, Tox_Group_Message_Id message_id, void *user_data); + Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type message_type, + const uint8_t message[], size_t message_length, Tox_Group_Message_Id message_id, void *user_data); /** * Set the callback for the `group_message` event. Pass NULL to unset. @@ -4746,14 +4934,18 @@ typedef void tox_group_message_cb( void tox_callback_group_message(Tox *tox, tox_group_message_cb *callback); /** - * @param group_number The group number of the group the private message is intended for. + * @param group_number The group number of the group the private message is + * intended for. * @param peer_id The ID of the peer who sent the private message. + * @param message_type The type of message (normal, action, ...). * @param message The message data. - * @param length The length of the message. + * @param message_length The length of the message. + * @param message_id A pseudo message id that clients can use to uniquely + * identify this group message. */ typedef void tox_group_private_message_cb( - Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type type, - const uint8_t message[], size_t length, Tox_Group_Message_Id message_id, void *user_data); + Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, Tox_Message_Type message_type, + const uint8_t message[], size_t message_length, Tox_Group_Message_Id message_id, void *user_data); /** * Set the callback for the `group_private_message` event. Pass NULL to unset. @@ -4766,11 +4958,11 @@ void tox_callback_group_private_message(Tox *tox, tox_group_private_message_cb * * @param group_number The group number of the group the packet is intended for. * @param peer_id The ID of the peer who sent the packet. * @param data The packet data. - * @param length The length of the data. + * @param data_length The length of the data. */ typedef void tox_group_custom_packet_cb( Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, - const uint8_t data[], size_t length, void *user_data); + const uint8_t data[], size_t data_length, void *user_data); /** * Set the callback for the `group_custom_packet` event. Pass NULL to unset. @@ -4783,14 +4975,15 @@ void tox_callback_group_custom_packet(Tox *tox, tox_group_custom_packet_cb *call * @param group_number The group number of the group the packet is intended for. * @param peer_id The ID of the peer who sent the packet. * @param data The packet data. - * @param length The length of the data. + * @param data_length The length of the data. */ typedef void tox_group_custom_private_packet_cb( Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, - const uint8_t data[], size_t length, void *user_data); + const uint8_t data[], size_t data_length, void *user_data); /** - * Set the callback for the `group_custom_private_packet` event. Pass NULL to unset. + * Set the callback for the `group_custom_private_packet` event. Pass NULL to + * unset. * * This event is triggered when the client receives a custom private packet. */ @@ -4820,7 +5013,8 @@ typedef enum Tox_Err_Group_Invite_Friend { TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND, /** - * Creation of the invite packet failed. This indicates a network related error. + * Creation of the invite packet failed. This indicates a network related + * error. */ TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL, @@ -4841,10 +5035,13 @@ const char *tox_err_group_invite_friend_to_string(Tox_Err_Group_Invite_Friend va /** * Invite a friend to a group. * - * This function creates an invite request packet and pushes it to the send queue. + * This function creates an invite request packet and pushes it to the send + * queue. * - * @param group_number The group number of the group the message is intended for. - * @param friend_number The friend number of the friend the invite is intended for. + * @param group_number The group number of the group the message is intended + * for. + * @param friend_number The friend number of the friend the invite is intended + * for. * * @return true on success. */ @@ -4880,36 +5077,44 @@ typedef enum Tox_Err_Group_Invite_Accept { TOX_ERR_GROUP_INVITE_ACCEPT_EMPTY, /** - * Failed to set password. This usually occurs if the password exceeds TOX_GROUP_MAX_PASSWORD_SIZE. + * Failed to set password. This usually occurs if the password exceeds + * TOX_GROUP_MAX_PASSWORD_SIZE. */ TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD, /** - * There was a core error when initiating the group. + * The friend number passed did not designate a valid friend. */ - TOX_ERR_GROUP_INVITE_ACCEPT_CORE, + TOX_ERR_GROUP_INVITE_ACCEPT_FRIEND_NOT_FOUND, /** * Packet failed to send. */ TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND, + /** + * Invite data or name is NULL. + */ + TOX_ERR_GROUP_INVITE_ACCEPT_NULL, + } Tox_Err_Group_Invite_Accept; const char *tox_err_group_invite_accept_to_string(Tox_Err_Group_Invite_Accept value); /** - * Accept an invite to a group chat that the client previously received from a friend. The invite - * is only valid while the inviter is present in the group. + * Accept an invite to a group chat that the client previously received from a + * friend. The invite is only valid while the inviter is present in the group. * * @param invite_data The invite data received from the `group_invite` event. * @param length The length of the invite data. * @param name The name of the peer joining the group. - * @param name_length The length of the peer's name. This must be greater than zero and no larger - * than TOX_MAX_NAME_LENGTH. - * @param password The password required to join the group. Set to NULL if no password is required. - * @param password_length The length of the password. If password_length is equal to zero, the password - * parameter will be ignored. password_length must be no larger than TOX_GROUP_MAX_PASSWORD_SIZE. + * @param name_length The length of the peer's name. This must be greater than + * zero and no larger than TOX_MAX_NAME_LENGTH. + * @param password The password required to join the group. Set to NULL if no + * password is required. + * @param password_length The length of the password. If password_length is + * equal to zero, the password parameter will be ignored. password_length + * must be no larger than TOX_GROUP_MAX_PASSWORD_SIZE. * * @return the group_number on success, UINT32_MAX on failure. */ @@ -4923,26 +5128,30 @@ Tox_Group_Number tox_group_invite_accept( /** * @param friend_number The friend number of the contact who sent the invite. * @param invite_data The invite data. - * @param length The length of invite_data. + * @param invite_data_length The length of invite_data. + * @param group_name The name of the group. In conferences, this is "title". + * @param group_name_length The length of the group name. */ typedef void tox_group_invite_cb( Tox *tox, Tox_Friend_Number friend_number, - const uint8_t invite_data[], size_t length, + const uint8_t invite_data[], size_t invite_data_length, const uint8_t group_name[], size_t group_name_length, void *user_data); /** * Set the callback for the `group_invite` event. Pass NULL to unset. * - * This event is triggered when the client receives a group invite from a friend. The client must store - * invite_data which is used to join the group via tox_group_invite_accept. + * This event is triggered when the client receives a group invite from a + * friend. The client must store invite_data which is used to join the group + * via tox_group_invite_accept. */ void tox_callback_group_invite(Tox *tox, tox_group_invite_cb *callback); /** - * @param group_number The group number of the group in which a new peer has joined. - * @param peer_id The permanent ID of the new peer. This id should not be relied on for - * client behaviour and should be treated as a random value. + * @param group_number The group number of the group in which a new peer has + * joined. + * @param peer_id The permanent ID of the new peer. This id should not be relied + * on for client behaviour and should be treated as a random value. */ typedef void tox_group_peer_join_cb(Tox *tox, Tox_Group_Number group_number, Tox_Group_Peer_Number peer_id, void *user_data); @@ -4954,7 +5163,8 @@ typedef void tox_group_peer_join_cb(Tox *tox, Tox_Group_Number group_number, Tox void tox_callback_group_peer_join(Tox *tox, tox_group_peer_join_cb *callback); /** - * Represents peer exit events. These should be used with the `group_peer_exit` event. + * Represents peer exit events. These should be used with the `group_peer_exit` + * event. */ typedef enum Tox_Group_Exit_Type { @@ -4974,8 +5184,9 @@ typedef enum Tox_Group_Exit_Type { TOX_GROUP_EXIT_TYPE_DISCONNECTED, /** - * Your connection with all peers has been severed. This will occur when you are kicked from - * a group, rejoin a group, or manually disconnect from a group. + * Your connection with all peers has been severed. This will occur when you + * are kicked from a group, rejoin a group, or manually disconnect from a + * group. */ TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED, @@ -4995,8 +5206,8 @@ const char *tox_group_exit_type_to_string(Tox_Group_Exit_Type value); /** * @param group_number The group number of the group in which a peer has left. - * @param peer_id The ID of the peer who left the group. This ID no longer designates a valid peer - * and cannot be used for API calls. + * @param peer_id The ID of the peer who left the group. This ID no longer + * designates a valid peer and cannot be used for API calls. * @param exit_type The type of exit event. One of Tox_Group_Exit_Type. * @param name The nickname of the peer who left the group. * @param name_length The length of the peer name. @@ -5023,14 +5234,14 @@ typedef void tox_group_self_join_cb(Tox *tox, Tox_Group_Number group_number, voi /** * Set the callback for the `group_self_join` event. Pass NULL to unset. * - * This event is triggered when the client has successfully joined a group. Use this to initialize - * any group information the client may need. + * This event is triggered when the client has successfully joined a group. Use + * this to initialize any group information the client may need. */ void tox_callback_group_self_join(Tox *tox, tox_group_self_join_cb *callback); /** - * Represents types of failed group join attempts. These are used in the tox_callback_group_rejected - * callback when a peer fails to join a group. + * Represents types of failed group join attempts. These are used in the + * tox_callback_group_rejected callback when a peer fails to join a group. */ typedef enum Tox_Group_Join_Fail { @@ -5045,8 +5256,8 @@ typedef enum Tox_Group_Join_Fail { TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD, /** - * The join attempt failed due to an unspecified error. This often occurs when the group is - * not found in the DHT. + * The join attempt failed due to an unspecified error. This often occurs + * when the group is not found in the DHT. */ TOX_GROUP_JOIN_FAIL_UNKNOWN, @@ -5055,7 +5266,8 @@ typedef enum Tox_Group_Join_Fail { const char *tox_group_join_fail_to_string(Tox_Group_Join_Fail value); /** - * @param group_number The group number of the group for which the join has failed. + * @param group_number The group number of the group for which the join has + * failed. * @param fail_type The type of group rejection. */ typedef void tox_group_join_fail_cb(Tox *tox, Tox_Group_Number group_number, Tox_Group_Join_Fail fail_type, void *user_data); @@ -5117,12 +5329,16 @@ const char *tox_err_group_set_password_to_string(Tox_Err_Group_Set_Password valu /** * Set or unset the group password. * - * This function allows Founders to set or unset a group password. It will create a new - * group shared state including the change and distribute it to the rest of the group. + * This function allows Founders to set or unset a group password. It will + * create a new group shared state including the change and distribute it to the + * rest of the group. * - * @param group_number The group number of the group for which we wish to set the password. - * @param password The password we want to set. Set password to NULL to unset the password. - * @param length The length of the password. length must be no longer than TOX_GROUP_MAX_PASSWORD_SIZE. + * @param group_number The group number of the group for which we wish to set + * the password. + * @param password The password we want to set. Set password to NULL to unset + * the password. + * @param length The length of the password. length must be no longer than + * TOX_GROUP_MAX_PASSWORD_SIZE. * * @return true on success. */ @@ -5154,8 +5370,8 @@ typedef enum Tox_Err_Group_Set_Topic_Lock { TOX_ERR_GROUP_SET_TOPIC_LOCK_PERMISSIONS, /** - * The topic lock could not be set. This may occur due to an error related to - * cryptographic signing of the new shared state. + * The topic lock could not be set. This may occur due to an error related + * to cryptographic signing of the new shared state. */ TOX_ERR_GROUP_SET_TOPIC_LOCK_FAIL_SET, @@ -5176,13 +5392,16 @@ const char *tox_err_group_set_topic_lock_to_string(Tox_Err_Group_Set_Topic_Lock /** * Set the group topic lock state. * - * This function allows Founders to enable or disable the group's topic lock. It will create a - * new shared state including the change and distribute it to the rest of the group. + * This function allows Founders to enable or disable the group's topic lock. It + * will create a new shared state including the change and distribute it to the + * rest of the group. * - * When the topic lock is enabled, only the group founder and moderators may set the topic. - * When disabled, all peers except those with the observer role may set the topic. + * When the topic lock is enabled, only the group founder and moderators may set + * the topic. When disabled, all peers except those with the observer role may + * set the topic. * - * @param group_number The group number of the group for which we wish to change the topic lock state. + * @param group_number The group number of the group for which we wish to change + * the topic lock state. * @param topic_lock The state we wish to set the topic lock to. * * @return true on success. @@ -5203,13 +5422,14 @@ typedef enum Tox_Err_Group_Set_Voice_State { TOX_ERR_GROUP_SET_VOICE_STATE_GROUP_NOT_FOUND, /** - * The caller does not have the required permissions to set the privacy state. + * The caller does not have the required permissions to set the privacy + * state. */ TOX_ERR_GROUP_SET_VOICE_STATE_PERMISSIONS, /** - * The voice state could not be set. This may occur due to an error related to - * cryptographic signing of the new shared state. + * The voice state could not be set. This may occur due to an error related + * to cryptographic signing of the new shared state. */ TOX_ERR_GROUP_SET_VOICE_STATE_FAIL_SET, @@ -5230,13 +5450,16 @@ const char *tox_err_group_set_voice_state_to_string(Tox_Err_Group_Set_Voice_Stat /** * Set the group voice state. * - * This function allows Founders to set the group's voice state. It will create a new group - * shared state including the change and distribute it to the rest of the group. + * This function allows Founders to set the group's voice state. It will create + * a new group shared state including the change and distribute it to the rest + * of the group. * - * If an attempt is made to set the voice state to the same state that the group is already - * in, the function call will be successful and no action will be taken. + * If an attempt is made to set the voice state to the same state that the group + * is already in, the function call will be successful and no action will be + * taken. * - * @param group_number The group number of the group for which we wish to change the voice state. + * @param group_number The group number of the group for which we wish to change + * the voice state. * @param voice_state The voice state we wish to set the group to. * * @return true on success. @@ -5257,13 +5480,14 @@ typedef enum Tox_Err_Group_Set_Privacy_State { TOX_ERR_GROUP_SET_PRIVACY_STATE_GROUP_NOT_FOUND, /** - * The caller does not have the required permissions to set the privacy state. + * The caller does not have the required permissions to set the privacy + * state. */ TOX_ERR_GROUP_SET_PRIVACY_STATE_PERMISSIONS, /** - * The privacy state could not be set. This may occur due to an error related to - * cryptographic signing of the new shared state. + * The privacy state could not be set. This may occur due to an error + * related to cryptographic signing of the new shared state. */ TOX_ERR_GROUP_SET_PRIVACY_STATE_FAIL_SET, @@ -5284,13 +5508,16 @@ const char *tox_err_group_set_privacy_state_to_string(Tox_Err_Group_Set_Privacy_ /** * Set the group privacy state. * - * This function allows Founders to set the group's privacy state. It will create a new group - * shared state including the change and distribute it to the rest of the group. + * This function allows Founders to set the group's privacy state. It will + * create a new group shared state including the change and distribute it to the + * rest of the group. * - * If an attempt is made to set the privacy state to the same state that the group is already - * in, the function call will be successful and no action will be taken. + * If an attempt is made to set the privacy state to the same state that the + * group is already in, the function call will be successful and no action will + * be taken. * - * @param group_number The group number of the group for which we wish to change the privacy state. + * @param group_number The group number of the group for which we wish to change + * the privacy state. * @param privacy_state The privacy state we wish to set the group to. * * @return true on success. @@ -5316,8 +5543,8 @@ typedef enum Tox_Err_Group_Set_Peer_Limit { TOX_ERR_GROUP_SET_PEER_LIMIT_PERMISSIONS, /** - * The peer limit could not be set. This may occur due to an error related to - * cryptographic signing of the new shared state. + * The peer limit could not be set. This may occur due to an error related + * to cryptographic signing of the new shared state. */ TOX_ERR_GROUP_SET_PEER_LIMIT_FAIL_SET, @@ -5338,11 +5565,12 @@ const char *tox_err_group_set_peer_limit_to_string(Tox_Err_Group_Set_Peer_Limit /** * Set the group peer limit. * - * This function allows Founders to set a limit for the number of peers who may be in the - * group. It will create a new group shared state including the change and distribute it to the - * rest of the group. + * This function allows Founders to set a limit for the number of peers who may + * be in the group. It will create a new group shared state including the change + * and distribute it to the rest of the group. * - * @param group_number The group number of the group for which we wish to set the peer limit. + * @param group_number The group number of the group for which we wish to set + * the peer limit. * @param peer_limit The maximum number of peers to allow in the group. * * @return true on success. @@ -5385,7 +5613,8 @@ const char *tox_err_group_set_ignore_to_string(Tox_Err_Group_Set_Ignore value); /** * Ignore or unignore a peer. * - * @param group_number The group number of the group in which you wish to ignore a peer. + * @param group_number The group number of the group in which you wish to ignore + * a peer. * @param peer_id The ID of the peer who shall be ignored or unignored. * @param ignore True to ignore the peer, false to unignore the peer. * @@ -5407,7 +5636,8 @@ typedef enum Tox_Err_Group_Set_Role { TOX_ERR_GROUP_SET_ROLE_GROUP_NOT_FOUND, /** - * The ID passed did not designate a valid peer. Note: you cannot set your own role. + * The ID passed did not designate a valid peer. Note: you cannot set your + * own role. */ TOX_ERR_GROUP_SET_ROLE_PEER_NOT_FOUND, @@ -5417,14 +5647,14 @@ typedef enum Tox_Err_Group_Set_Role { TOX_ERR_GROUP_SET_ROLE_PERMISSIONS, /** - * The role assignment is invalid. This will occur if you try to set a peer's role to - * the role they already have. + * The role assignment is invalid. This will occur if you try to set a + * peer's role to the role they already have. */ TOX_ERR_GROUP_SET_ROLE_ASSIGNMENT, /** - * The role was not successfully set. This may occur if the packet failed to send, or - * if the role limit has been reached. + * The role was not successfully set. This may occur if the packet failed to + * send, or if the role limit has been reached. */ TOX_ERR_GROUP_SET_ROLE_FAIL_ACTION, @@ -5440,15 +5670,17 @@ const char *tox_err_group_set_role_to_string(Tox_Err_Group_Set_Role value); /** * Set a peer's role. * - * This function will first remove the peer's previous role and then assign them a new role. - * It will also send a packet to the rest of the group, requesting that they perform - * the role reassignment. + * This function will first remove the peer's previous role and then assign them + * a new role. It will also send a packet to the rest of the group, requesting + * that they perform the role reassignment. * - * Only Founders may promote peers to the Moderator role, and only Founders and Moderators may - * set peers to the Observer or User role. Moderators may not set the role of other Moderators - * or the Founder. Peers may not be promoted to the Founder role. + * Only Founders may promote peers to the Moderator role, and only Founders and + * Moderators may set peers to the Observer or User role. Moderators may not set + * the role of other Moderators or the Founder. Peers may not be promoted to the + * Founder role. * - * @param group_number The group number of the group the in which you wish set the peer's role. + * @param group_number The group number of the group the in which you wish set + * the peer's role. * @param peer_id The ID of the peer whose role you wish to set. * @param role The role you wish to set the peer to. * @@ -5501,10 +5733,12 @@ const char *tox_err_group_kick_peer_to_string(Tox_Err_Group_Kick_Peer value); /** * Kick a peer. * - * This function allows peers with the Founder or Moderator role to silently instruct - * all other peers in the group to remove a particular peer from their peer list. + * This function allows peers with the Founder or Moderator role to silently + * instruct all other peers in the group to remove a particular peer from their + * peer list. * - * Note: This function will not trigger the `group_peer_exit` event for the caller. + * Note: This function will not trigger the `group_peer_exit` event for the + * caller. * * @param group_number The group number of the group the action is intended for. * @param peer_id The ID of the peer who will be kicked. @@ -5515,7 +5749,8 @@ bool tox_group_kick_peer(const Tox *tox, Tox_Group_Number group_number, Tox_Grou Tox_Err_Group_Kick_Peer *error); /** - * Represents moderation events. These should be used with the `group_moderation` event. + * Represents moderation events. These should be used with the + * `group_moderation` event. */ typedef enum Tox_Group_Mod_Event { @@ -5556,12 +5791,13 @@ typedef void tox_group_moderation_cb( /** * Set the callback for the `group_moderation` event. Pass NULL to unset. * - * This event is triggered when a moderator or founder executes a moderation event, with - * the exception of the peer who initiates the event. It is also triggered when the - * observer and moderator lists are silently modified (this may occur during group syncing). + * This event is triggered when a moderator or founder executes a moderation + * event, with the exception of the peer who initiates the event. It is also + * triggered when the observer and moderator lists are silently modified (this + * may occur during group syncing). * - * If either peer id does not designate a valid peer in the group chat, the client should - * manually update all peer roles. + * If either peer id does not designate a valid peer in the group chat, the + * client should manually update all peer roles. */ void tox_callback_group_moderation(Tox *tox, tox_group_moderation_cb *callback); diff --git a/toxcore/tox_api.c b/toxcore/tox_api.c index 5904c803af..b979e4e1e2 100644 --- a/toxcore/tox_api.c +++ b/toxcore/tox_api.c @@ -265,14 +265,6 @@ void tox_options_set_experimental_thread_safety( { options->experimental_thread_safety = experimental_thread_safety; } -const Tox_System *tox_options_get_operating_system(const Tox_Options *options) -{ - return options->operating_system; -} -void tox_options_set_operating_system(Tox_Options *options, const Tox_System *operating_system) -{ - options->operating_system = operating_system; -} bool tox_options_get_experimental_groups_persistence(const Tox_Options *options) { return options->experimental_groups_persistence; @@ -282,6 +274,14 @@ void tox_options_set_experimental_groups_persistence( { options->experimental_groups_persistence = experimental_groups_persistence; } +bool tox_options_get_experimental_disable_dns(const Tox_Options *options) +{ + return options->experimental_disable_dns; +} +void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experimental_disable_dns) +{ + options->experimental_disable_dns = experimental_disable_dns; +} const uint8_t *tox_options_get_savedata_data(const Tox_Options *options) { @@ -307,6 +307,7 @@ void tox_options_default(Tox_Options *options) tox_options_set_dht_announcements_enabled(options, true); tox_options_set_experimental_thread_safety(options, false); tox_options_set_experimental_groups_persistence(options, false); + tox_options_set_experimental_disable_dns(options, false); } } @@ -895,6 +896,9 @@ const char *tox_err_conference_join_to_string(Tox_Err_Conference_Join value) case TOX_ERR_CONFERENCE_JOIN_FAIL_SEND: return "TOX_ERR_CONFERENCE_JOIN_FAIL_SEND"; + + case TOX_ERR_CONFERENCE_JOIN_NULL: + return "TOX_ERR_CONFERENCE_JOIN_NULL"; } return ""; @@ -1340,6 +1344,9 @@ const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Priv case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY: return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY"; + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE: + return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE"; + case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS: return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS"; @@ -1348,9 +1355,6 @@ const char *tox_err_group_send_private_message_to_string(Tox_Err_Group_Send_Priv case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED: return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED"; - - case TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE: - return "TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE"; } return ""; @@ -1451,11 +1455,14 @@ const char *tox_err_group_invite_accept_to_string(Tox_Err_Group_Invite_Accept va case TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD: return "TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD"; - case TOX_ERR_GROUP_INVITE_ACCEPT_CORE: - return "TOX_ERR_GROUP_INVITE_ACCEPT_CORE"; + case TOX_ERR_GROUP_INVITE_ACCEPT_FRIEND_NOT_FOUND: + return "TOX_ERR_GROUP_INVITE_ACCEPT_FRIEND_NOT_FOUND"; case TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND: return "TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND"; + + case TOX_ERR_GROUP_INVITE_ACCEPT_NULL: + return "TOX_ERR_GROUP_INVITE_ACCEPT_NULL"; } return ""; diff --git a/toxcore/tox_dispatch.h b/toxcore/tox_dispatch.h index 2588065a4d..29ac66a412 100644 --- a/toxcore/tox_dispatch.h +++ b/toxcore/tox_dispatch.h @@ -2,6 +2,13 @@ * Copyright © 2022 The TokTok team. */ +/** + * WARNING: This is an experimental API and is subject to change. + * + * At this point, it probably won't change very much anymore, but we may have + * small breaking changes before a stable release. + */ + #ifndef C_TOXCORE_TOXCORE_TOX_DISPATCH_H #define C_TOXCORE_TOXCORE_TOX_DISPATCH_H diff --git a/toxcore/tox_event.c b/toxcore/tox_event.c index b0a65503cd..f702d629fc 100644 --- a/toxcore/tox_event.c +++ b/toxcore/tox_event.c @@ -725,216 +725,216 @@ bool tox_event_pack(const Tox_Event *event, Bin_Pack *bp) } non_null() -static bool tox_event_type_from_int(uint32_t value, Tox_Event_Type *out) +static bool tox_event_type_from_int(uint32_t value, Tox_Event_Type *out_enum) { switch (value) { case TOX_EVENT_SELF_CONNECTION_STATUS: { - *out = TOX_EVENT_SELF_CONNECTION_STATUS; + *out_enum = TOX_EVENT_SELF_CONNECTION_STATUS; return true; } case TOX_EVENT_FRIEND_REQUEST: { - *out = TOX_EVENT_FRIEND_REQUEST; + *out_enum = TOX_EVENT_FRIEND_REQUEST; return true; } case TOX_EVENT_FRIEND_CONNECTION_STATUS: { - *out = TOX_EVENT_FRIEND_CONNECTION_STATUS; + *out_enum = TOX_EVENT_FRIEND_CONNECTION_STATUS; return true; } case TOX_EVENT_FRIEND_LOSSY_PACKET: { - *out = TOX_EVENT_FRIEND_LOSSY_PACKET; + *out_enum = TOX_EVENT_FRIEND_LOSSY_PACKET; return true; } case TOX_EVENT_FRIEND_LOSSLESS_PACKET: { - *out = TOX_EVENT_FRIEND_LOSSLESS_PACKET; + *out_enum = TOX_EVENT_FRIEND_LOSSLESS_PACKET; return true; } case TOX_EVENT_FRIEND_NAME: { - *out = TOX_EVENT_FRIEND_NAME; + *out_enum = TOX_EVENT_FRIEND_NAME; return true; } case TOX_EVENT_FRIEND_STATUS: { - *out = TOX_EVENT_FRIEND_STATUS; + *out_enum = TOX_EVENT_FRIEND_STATUS; return true; } case TOX_EVENT_FRIEND_STATUS_MESSAGE: { - *out = TOX_EVENT_FRIEND_STATUS_MESSAGE; + *out_enum = TOX_EVENT_FRIEND_STATUS_MESSAGE; return true; } case TOX_EVENT_FRIEND_MESSAGE: { - *out = TOX_EVENT_FRIEND_MESSAGE; + *out_enum = TOX_EVENT_FRIEND_MESSAGE; return true; } case TOX_EVENT_FRIEND_READ_RECEIPT: { - *out = TOX_EVENT_FRIEND_READ_RECEIPT; + *out_enum = TOX_EVENT_FRIEND_READ_RECEIPT; return true; } case TOX_EVENT_FRIEND_TYPING: { - *out = TOX_EVENT_FRIEND_TYPING; + *out_enum = TOX_EVENT_FRIEND_TYPING; return true; } case TOX_EVENT_FILE_CHUNK_REQUEST: { - *out = TOX_EVENT_FILE_CHUNK_REQUEST; + *out_enum = TOX_EVENT_FILE_CHUNK_REQUEST; return true; } case TOX_EVENT_FILE_RECV: { - *out = TOX_EVENT_FILE_RECV; + *out_enum = TOX_EVENT_FILE_RECV; return true; } case TOX_EVENT_FILE_RECV_CHUNK: { - *out = TOX_EVENT_FILE_RECV_CHUNK; + *out_enum = TOX_EVENT_FILE_RECV_CHUNK; return true; } case TOX_EVENT_FILE_RECV_CONTROL: { - *out = TOX_EVENT_FILE_RECV_CONTROL; + *out_enum = TOX_EVENT_FILE_RECV_CONTROL; return true; } case TOX_EVENT_CONFERENCE_INVITE: { - *out = TOX_EVENT_CONFERENCE_INVITE; + *out_enum = TOX_EVENT_CONFERENCE_INVITE; return true; } case TOX_EVENT_CONFERENCE_CONNECTED: { - *out = TOX_EVENT_CONFERENCE_CONNECTED; + *out_enum = TOX_EVENT_CONFERENCE_CONNECTED; return true; } case TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED: { - *out = TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED; + *out_enum = TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED; return true; } case TOX_EVENT_CONFERENCE_PEER_NAME: { - *out = TOX_EVENT_CONFERENCE_PEER_NAME; + *out_enum = TOX_EVENT_CONFERENCE_PEER_NAME; return true; } case TOX_EVENT_CONFERENCE_TITLE: { - *out = TOX_EVENT_CONFERENCE_TITLE; + *out_enum = TOX_EVENT_CONFERENCE_TITLE; return true; } case TOX_EVENT_CONFERENCE_MESSAGE: { - *out = TOX_EVENT_CONFERENCE_MESSAGE; + *out_enum = TOX_EVENT_CONFERENCE_MESSAGE; return true; } case TOX_EVENT_GROUP_PEER_NAME: { - *out = TOX_EVENT_GROUP_PEER_NAME; + *out_enum = TOX_EVENT_GROUP_PEER_NAME; return true; } case TOX_EVENT_GROUP_PEER_STATUS: { - *out = TOX_EVENT_GROUP_PEER_STATUS; + *out_enum = TOX_EVENT_GROUP_PEER_STATUS; return true; } case TOX_EVENT_GROUP_TOPIC: { - *out = TOX_EVENT_GROUP_TOPIC; + *out_enum = TOX_EVENT_GROUP_TOPIC; return true; } case TOX_EVENT_GROUP_PRIVACY_STATE: { - *out = TOX_EVENT_GROUP_PRIVACY_STATE; + *out_enum = TOX_EVENT_GROUP_PRIVACY_STATE; return true; } case TOX_EVENT_GROUP_VOICE_STATE: { - *out = TOX_EVENT_GROUP_VOICE_STATE; + *out_enum = TOX_EVENT_GROUP_VOICE_STATE; return true; } case TOX_EVENT_GROUP_TOPIC_LOCK: { - *out = TOX_EVENT_GROUP_TOPIC_LOCK; + *out_enum = TOX_EVENT_GROUP_TOPIC_LOCK; return true; } case TOX_EVENT_GROUP_PEER_LIMIT: { - *out = TOX_EVENT_GROUP_PEER_LIMIT; + *out_enum = TOX_EVENT_GROUP_PEER_LIMIT; return true; } case TOX_EVENT_GROUP_PASSWORD: { - *out = TOX_EVENT_GROUP_PASSWORD; + *out_enum = TOX_EVENT_GROUP_PASSWORD; return true; } case TOX_EVENT_GROUP_MESSAGE: { - *out = TOX_EVENT_GROUP_MESSAGE; + *out_enum = TOX_EVENT_GROUP_MESSAGE; return true; } case TOX_EVENT_GROUP_PRIVATE_MESSAGE: { - *out = TOX_EVENT_GROUP_PRIVATE_MESSAGE; + *out_enum = TOX_EVENT_GROUP_PRIVATE_MESSAGE; return true; } case TOX_EVENT_GROUP_CUSTOM_PACKET: { - *out = TOX_EVENT_GROUP_CUSTOM_PACKET; + *out_enum = TOX_EVENT_GROUP_CUSTOM_PACKET; return true; } case TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET: { - *out = TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET; + *out_enum = TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET; return true; } case TOX_EVENT_GROUP_INVITE: { - *out = TOX_EVENT_GROUP_INVITE; + *out_enum = TOX_EVENT_GROUP_INVITE; return true; } case TOX_EVENT_GROUP_PEER_JOIN: { - *out = TOX_EVENT_GROUP_PEER_JOIN; + *out_enum = TOX_EVENT_GROUP_PEER_JOIN; return true; } case TOX_EVENT_GROUP_PEER_EXIT: { - *out = TOX_EVENT_GROUP_PEER_EXIT; + *out_enum = TOX_EVENT_GROUP_PEER_EXIT; return true; } case TOX_EVENT_GROUP_SELF_JOIN: { - *out = TOX_EVENT_GROUP_SELF_JOIN; + *out_enum = TOX_EVENT_GROUP_SELF_JOIN; return true; } case TOX_EVENT_GROUP_JOIN_FAIL: { - *out = TOX_EVENT_GROUP_JOIN_FAIL; + *out_enum = TOX_EVENT_GROUP_JOIN_FAIL; return true; } case TOX_EVENT_GROUP_MODERATION: { - *out = TOX_EVENT_GROUP_MODERATION; + *out_enum = TOX_EVENT_GROUP_MODERATION; return true; } case TOX_EVENT_DHT_GET_NODES_RESPONSE: { - *out = TOX_EVENT_DHT_GET_NODES_RESPONSE; + *out_enum = TOX_EVENT_DHT_GET_NODES_RESPONSE; return true; } case TOX_EVENT_INVALID: { - *out = TOX_EVENT_INVALID; + *out_enum = TOX_EVENT_INVALID; return true; } default: { - *out = TOX_EVENT_INVALID; + *out_enum = TOX_EVENT_INVALID; return false; } } diff --git a/toxcore/tox_events.h b/toxcore/tox_events.h index 73068829e0..6bbf13e8ef 100644 --- a/toxcore/tox_events.h +++ b/toxcore/tox_events.h @@ -2,6 +2,13 @@ * Copyright © 2022-2024 The TokTok team. */ +/** + * WARNING: This is an experimental API and is subject to change. + * + * At this point, it probably won't change very much anymore, but we may have + * small breaking changes before a stable release. + */ + #ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_H #define C_TOXCORE_TOXCORE_TOX_EVENTS_H @@ -248,7 +255,7 @@ uint32_t tox_event_group_message_get_group_number( const Tox_Event_Group_Message *group_message); uint32_t tox_event_group_message_get_peer_id( const Tox_Event_Group_Message *group_message); -Tox_Message_Type tox_event_group_message_get_type( +Tox_Message_Type tox_event_group_message_get_message_type( const Tox_Event_Group_Message *group_message); const uint8_t *tox_event_group_message_get_message( const Tox_Event_Group_Message *group_message); @@ -262,7 +269,7 @@ uint32_t tox_event_group_private_message_get_group_number( const Tox_Event_Group_Private_Message *group_private_message); uint32_t tox_event_group_private_message_get_peer_id( const Tox_Event_Group_Private_Message *group_private_message); -Tox_Message_Type tox_event_group_private_message_get_type( +Tox_Message_Type tox_event_group_private_message_get_message_type( const Tox_Event_Group_Private_Message *group_private_message); const uint8_t *tox_event_group_private_message_get_message( const Tox_Event_Group_Private_Message *group_private_message); @@ -570,6 +577,8 @@ void tox_events_free(Tox_Events *events); uint32_t tox_events_bytes_size(const Tox_Events *events); bool tox_events_get_bytes(const Tox_Events *events, uint8_t *bytes); +typedef struct Tox_System Tox_System; + Tox_Events *tox_events_load(const Tox_System *sys, const uint8_t *bytes, uint32_t bytes_size); bool tox_events_equal(const Tox_System *sys, const Tox_Events *a, const Tox_Events *b); diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index 7b6050a9f8..ff6aa6e19d 100644 --- a/toxcore/tox_private.c +++ b/toxcore/tox_private.c @@ -124,7 +124,7 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip IP_Port *root; - const int32_t count = net_getipport(tox->sys.mem, ip, &root, TOX_SOCK_DGRAM); + const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, ip, &root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled); if (count < 1) { SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_BAD_IP); diff --git a/toxcore/tox_private.h b/toxcore/tox_private.h index d36ab026c3..c872bfea47 100644 --- a/toxcore/tox_private.h +++ b/toxcore/tox_private.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2020 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013 Tox project. */ @@ -18,38 +18,49 @@ extern "C" { typedef uint64_t tox_mono_time_cb(void *user_data); -struct Tox_System { +typedef struct Tox_System { tox_mono_time_cb *mono_time_callback; void *mono_time_user_data; const struct Random *rng; const struct Network *ns; const struct Memory *mem; -}; +} Tox_System; Tox_System tox_default_system(void); +const Tox_System *tox_get_system(Tox *tox); + +typedef struct Tox_Options_Testing { + const struct Tox_System *operating_system; +} Tox_Options_Testing; + +typedef enum Tox_Err_New_Testing { + TOX_ERR_NEW_TESTING_OK, + TOX_ERR_NEW_TESTING_NULL, +} Tox_Err_New_Testing; + +Tox *tox_new_testing(const Tox_Options *options, Tox_Err_New *error, const Tox_Options_Testing *testing, Tox_Err_New_Testing *testing_error); + void tox_lock(const Tox *tox); void tox_unlock(const Tox *tox); -const Tox_System *tox_get_system(Tox *tox); - /** - * Set the callback for the `friend_lossy_packet` event for a specific packet ID. - * Pass NULL to unset. + * Set the callback for the `friend_lossy_packet` event for a specific packet + * ID. Pass NULL to unset. * * allowed packet ID range: - * from `PACKET_ID_RANGE_LOSSY_START` to `PACKET_ID_RANGE_LOSSY_END` (both inclusive) + * from `PACKET_ID_RANGE_LOSSY_START` to `PACKET_ID_RANGE_LOSSY_END` (both + * inclusive) */ void tox_callback_friend_lossy_packet_per_pktid(Tox *tox, tox_friend_lossy_packet_cb *callback, uint8_t pktid); /** - * Set the callback for the `friend_lossless_packet` event for a specific packet ID. - * Pass NULL to unset. + * Set the callback for the `friend_lossless_packet` event for a specific packet + * ID. Pass NULL to unset. * * allowed packet ID range: - * from `PACKET_ID_RANGE_LOSSLESS_CUSTOM_START` to `PACKET_ID_RANGE_LOSSLESS_CUSTOM_END` (both inclusive) - * and - * `PACKET_ID_MSI` + * from `PACKET_ID_RANGE_LOSSLESS_CUSTOM_START` to + * `PACKET_ID_RANGE_LOSSLESS_CUSTOM_END` (both inclusive) and `PACKET_ID_MSI` */ void tox_callback_friend_lossless_packet_per_pktid(Tox *tox, tox_friend_lossless_packet_cb *callback, uint8_t pktid); @@ -78,7 +89,7 @@ uint32_t tox_dht_node_public_key_size(void); /** * @param public_key The node's public key. - * @param ip The node's IP address, represented as a null terminated string. + * @param ip The node's IP address, represented as a NUL-terminated C string. * @param port The node's port. */ typedef void tox_dht_get_nodes_response_cb(Tox *tox, const uint8_t *public_key, const char *ip, uint16_t port, @@ -98,7 +109,8 @@ typedef enum Tox_Err_Dht_Get_Nodes { TOX_ERR_DHT_GET_NODES_OK, /** - * UDP is disabled in tox options; the DHT can only be queried when UDP is enabled. + * UDP is disabled in Tox options; the DHT can only be queried when UDP is + * enabled. */ TOX_ERR_DHT_GET_NODES_UDP_DISABLED, @@ -118,21 +130,24 @@ typedef enum Tox_Err_Dht_Get_Nodes { TOX_ERR_DHT_GET_NODES_BAD_IP, /** - * The getnodes request failed. This usually means the packet failed to send. + * The getnodes request failed. This usually means the packet failed to + * send. */ TOX_ERR_DHT_GET_NODES_FAIL, } Tox_Err_Dht_Get_Nodes; /** * This function sends a getnodes request to a DHT node for its peers that - * are "close" to the passed target public key according to the distance metric used - * by the DHT implementation. + * are "close" to the passed target public key according to the distance metric + * used by the DHT implementation. * - * @param public_key The public key of the node that we wish to query. This key must be - * at least `TOX_DHT_NODE_PUBLIC_KEY_SIZE` bytes in length. - * @param ip A NULL terminated string representing the IP address of the node we wish to query. + * @param public_key The public key of the node that we wish to query. This key + * must be at least `TOX_DHT_NODE_PUBLIC_KEY_SIZE` bytes in length. + * @param ip A NUL-terminated C string representing the IP address of the node + * we wish to query. * @param port The port of the node we wish to query. - * @param target_public_key The public key for which we want to find close nodes. + * @param target_public_key The public key for which we want to find close + * nodes. * * @return true on success. */ @@ -140,7 +155,6 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip const uint8_t *target_public_key, Tox_Err_Dht_Get_Nodes *error); /** - * This function returns the ratio of close dht nodes that are known to support announce/store. * This function returns the number of DHT nodes in the closelist. * * @return number @@ -148,8 +162,8 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip uint16_t tox_dht_get_num_closelist(const Tox *tox); /** - * This function returns the number of DHT nodes in the closelist, - * that are capable to store annouce data (introduced in version 0.2.18). + * This function returns the number of DHT nodes in the closelist + * that are capable of storing announce data (introduced in version 0.2.18). * * @return number */ @@ -169,30 +183,32 @@ uint16_t tox_dht_get_num_closelist_announce_capable(const Tox *tox); uint32_t tox_group_peer_ip_string_max_length(void); /** - * Return the length of the peer's IP address in string form. If the group number or ID - * is invalid, the return value is unspecified. + * Return the length of the peer's IP address in string form. If the group + * number or ID is invalid, the return value is unspecified. * * @param group_number The group number of the group we wish to query. - * @param peer_id The ID of the peer whose IP address length we want to retrieve. + * @param peer_id The ID of the peer whose IP address length we want to + * retrieve. */ size_t tox_group_peer_get_ip_address_size(const Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Err_Group_Peer_Query *error); /** - * Write the IP address associated with the designated peer_id for the designated group number - * to ip_addr. + * Write the IP address associated with the designated peer_id for the + * designated group number to ip_addr. * - * If the peer is forcing TCP connections a placeholder value will be written instead, - * indicating that their real IP address is unknown to us. + * If the peer is forcing TCP connections a placeholder value will be written + * instead, indicating that their real IP address is unknown to us. * - * If `peer_id` designates ourself, it will write either our own IP address or a placeholder value, - * depending on whether or not we're forcing TCP connections. + * If `peer_id` designates ourself, it will write either our own IP address or a + * placeholder value, depending on whether or not we're forcing TCP connections. * - * Call tox_group_peer_get_ip_address_size to determine the allocation size for the `ip_addr` parameter. + * Call tox_group_peer_get_ip_address_size to determine the allocation size for + * the `ip_addr` parameter. * * @param group_number The group number of the group we wish to query. * @param peer_id The ID of the peer whose public key we wish to retrieve. - * @param ip_addr A valid memory region large enough to store the IP address string. - * If this parameter is NULL, this function call has no effect. + * @param ip_addr A valid memory region large enough to store the IP address + * string. If this parameter is NULL, this function call has no effect. * * @return true on success. */ diff --git a/toxcore/tox_struct.h b/toxcore/tox_struct.h index bd42fcce8d..6e6af78ee1 100644 --- a/toxcore/tox_struct.h +++ b/toxcore/tox_struct.h @@ -66,6 +66,16 @@ struct Tox { tox_group_join_fail_cb *group_join_fail_callback; tox_group_moderation_cb *group_moderation_callback; + tox_loop_begin_cb *loop_begin_callback; + tox_loop_end_cb *loop_end_callback; + +#ifdef HAVE_LIBEV + struct ev_loop *dispatcher; + ev_async stop_loop; +#else + bool loop_run; +#endif + void *toxav_object; // workaround to store a ToxAV object (setter and getter functions are available) }; diff --git a/toxcore/tox_unpack.c b/toxcore/tox_unpack.c index b5e05da872..5caef02c07 100644 --- a/toxcore/tox_unpack.c +++ b/toxcore/tox_unpack.c @@ -11,21 +11,21 @@ #include "tox.h" non_null() -static bool tox_conference_type_from_int(uint32_t value, Tox_Conference_Type *out) +static bool tox_conference_type_from_int(uint32_t value, Tox_Conference_Type *out_enum) { switch (value) { case TOX_CONFERENCE_TYPE_TEXT: { - *out = TOX_CONFERENCE_TYPE_TEXT; + *out_enum = TOX_CONFERENCE_TYPE_TEXT; return true; } case TOX_CONFERENCE_TYPE_AV: { - *out = TOX_CONFERENCE_TYPE_AV; + *out_enum = TOX_CONFERENCE_TYPE_AV; return true; } default: { - *out = TOX_CONFERENCE_TYPE_TEXT; + *out_enum = TOX_CONFERENCE_TYPE_TEXT; return false; } } @@ -38,26 +38,26 @@ bool tox_conference_type_unpack(Tox_Conference_Type *val, Bin_Unpack *bu) } non_null() -static bool tox_connection_from_int(uint32_t value, Tox_Connection *out) +static bool tox_connection_from_int(uint32_t value, Tox_Connection *out_enum) { switch (value) { case TOX_CONNECTION_NONE: { - *out = TOX_CONNECTION_NONE; + *out_enum = TOX_CONNECTION_NONE; return true; } case TOX_CONNECTION_TCP: { - *out = TOX_CONNECTION_TCP; + *out_enum = TOX_CONNECTION_TCP; return true; } case TOX_CONNECTION_UDP: { - *out = TOX_CONNECTION_UDP; + *out_enum = TOX_CONNECTION_UDP; return true; } default: { - *out = TOX_CONNECTION_NONE; + *out_enum = TOX_CONNECTION_NONE; return false; } } @@ -71,26 +71,26 @@ bool tox_connection_unpack(Tox_Connection *val, Bin_Unpack *bu) } non_null() -static bool tox_file_control_from_int(uint32_t value, Tox_File_Control *out) +static bool tox_file_control_from_int(uint32_t value, Tox_File_Control *out_enum) { switch (value) { case TOX_FILE_CONTROL_RESUME: { - *out = TOX_FILE_CONTROL_RESUME; + *out_enum = TOX_FILE_CONTROL_RESUME; return true; } case TOX_FILE_CONTROL_PAUSE: { - *out = TOX_FILE_CONTROL_PAUSE; + *out_enum = TOX_FILE_CONTROL_PAUSE; return true; } case TOX_FILE_CONTROL_CANCEL: { - *out = TOX_FILE_CONTROL_CANCEL; + *out_enum = TOX_FILE_CONTROL_CANCEL; return true; } default: { - *out = TOX_FILE_CONTROL_RESUME; + *out_enum = TOX_FILE_CONTROL_RESUME; return false; } } @@ -104,21 +104,21 @@ bool tox_file_control_unpack(Tox_File_Control *val, Bin_Unpack *bu) } non_null() -static bool tox_message_type_from_int(uint32_t value, Tox_Message_Type *out) +static bool tox_message_type_from_int(uint32_t value, Tox_Message_Type *out_enum) { switch (value) { case TOX_MESSAGE_TYPE_NORMAL: { - *out = TOX_MESSAGE_TYPE_NORMAL; + *out_enum = TOX_MESSAGE_TYPE_NORMAL; return true; } case TOX_MESSAGE_TYPE_ACTION: { - *out = TOX_MESSAGE_TYPE_ACTION; + *out_enum = TOX_MESSAGE_TYPE_ACTION; return true; } default: { - *out = TOX_MESSAGE_TYPE_NORMAL; + *out_enum = TOX_MESSAGE_TYPE_NORMAL; return false; } } @@ -132,26 +132,26 @@ bool tox_message_type_unpack(Tox_Message_Type *val, Bin_Unpack *bu) } non_null() -static bool tox_user_status_from_int(uint32_t value, Tox_User_Status *out) +static bool tox_user_status_from_int(uint32_t value, Tox_User_Status *out_enum) { switch (value) { case TOX_USER_STATUS_NONE: { - *out = TOX_USER_STATUS_NONE; + *out_enum = TOX_USER_STATUS_NONE; return true; } case TOX_USER_STATUS_AWAY: { - *out = TOX_USER_STATUS_AWAY; + *out_enum = TOX_USER_STATUS_AWAY; return true; } case TOX_USER_STATUS_BUSY: { - *out = TOX_USER_STATUS_BUSY; + *out_enum = TOX_USER_STATUS_BUSY; return true; } default: { - *out = TOX_USER_STATUS_NONE; + *out_enum = TOX_USER_STATUS_NONE; return false; } } @@ -165,19 +165,19 @@ bool tox_user_status_unpack(Tox_User_Status *val, Bin_Unpack *bu) } non_null() -static bool tox_group_privacy_state_from_int(uint32_t value, Tox_Group_Privacy_State *out) +static bool tox_group_privacy_state_from_int(uint32_t value, Tox_Group_Privacy_State *out_enum) { switch (value) { case TOX_GROUP_PRIVACY_STATE_PUBLIC: { - *out = TOX_GROUP_PRIVACY_STATE_PUBLIC; + *out_enum = TOX_GROUP_PRIVACY_STATE_PUBLIC; return true; } case TOX_GROUP_PRIVACY_STATE_PRIVATE: { - *out = TOX_GROUP_PRIVACY_STATE_PRIVATE; + *out_enum = TOX_GROUP_PRIVACY_STATE_PRIVATE; return true; } default: { - *out = TOX_GROUP_PRIVACY_STATE_PUBLIC; + *out_enum = TOX_GROUP_PRIVACY_STATE_PUBLIC; return false; } } @@ -189,23 +189,23 @@ bool tox_group_privacy_state_unpack(Tox_Group_Privacy_State *val, Bin_Unpack *bu && tox_group_privacy_state_from_int(u32, val); } non_null() -static bool tox_group_voice_state_from_int(uint32_t value, Tox_Group_Voice_State *out) +static bool tox_group_voice_state_from_int(uint32_t value, Tox_Group_Voice_State *out_enum) { switch (value) { case TOX_GROUP_VOICE_STATE_ALL: { - *out = TOX_GROUP_VOICE_STATE_ALL; + *out_enum = TOX_GROUP_VOICE_STATE_ALL; return true; } case TOX_GROUP_VOICE_STATE_MODERATOR: { - *out = TOX_GROUP_VOICE_STATE_MODERATOR; + *out_enum = TOX_GROUP_VOICE_STATE_MODERATOR; return true; } case TOX_GROUP_VOICE_STATE_FOUNDER: { - *out = TOX_GROUP_VOICE_STATE_FOUNDER; + *out_enum = TOX_GROUP_VOICE_STATE_FOUNDER; return true; } default: { - *out = TOX_GROUP_VOICE_STATE_ALL; + *out_enum = TOX_GROUP_VOICE_STATE_ALL; return false; } } @@ -218,19 +218,19 @@ bool tox_group_voice_state_unpack(Tox_Group_Voice_State *val, Bin_Unpack *bu) } non_null() -static bool tox_group_topic_lock_from_int(uint32_t value, Tox_Group_Topic_Lock *out) +static bool tox_group_topic_lock_from_int(uint32_t value, Tox_Group_Topic_Lock *out_enum) { switch (value) { case TOX_GROUP_TOPIC_LOCK_ENABLED: { - *out = TOX_GROUP_TOPIC_LOCK_ENABLED; + *out_enum = TOX_GROUP_TOPIC_LOCK_ENABLED; return true; } case TOX_GROUP_TOPIC_LOCK_DISABLED: { - *out = TOX_GROUP_TOPIC_LOCK_DISABLED; + *out_enum = TOX_GROUP_TOPIC_LOCK_DISABLED; return true; } default: { - *out = TOX_GROUP_TOPIC_LOCK_ENABLED; + *out_enum = TOX_GROUP_TOPIC_LOCK_ENABLED; return false; } } @@ -243,23 +243,23 @@ bool tox_group_topic_lock_unpack(Tox_Group_Topic_Lock *val, Bin_Unpack *bu) } non_null() -static bool tox_group_join_fail_from_int(uint32_t value, Tox_Group_Join_Fail *out) +static bool tox_group_join_fail_from_int(uint32_t value, Tox_Group_Join_Fail *out_enum) { switch (value) { case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: { - *out = TOX_GROUP_JOIN_FAIL_PEER_LIMIT; + *out_enum = TOX_GROUP_JOIN_FAIL_PEER_LIMIT; return true; } case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: { - *out = TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD; + *out_enum = TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD; return true; } case TOX_GROUP_JOIN_FAIL_UNKNOWN: { - *out = TOX_GROUP_JOIN_FAIL_UNKNOWN; + *out_enum = TOX_GROUP_JOIN_FAIL_UNKNOWN; return true; } default: { - *out = TOX_GROUP_JOIN_FAIL_PEER_LIMIT; + *out_enum = TOX_GROUP_JOIN_FAIL_PEER_LIMIT; return false; } } @@ -272,27 +272,27 @@ bool tox_group_join_fail_unpack(Tox_Group_Join_Fail *val, Bin_Unpack *bu) } non_null() -static bool tox_group_mod_event_from_int(uint32_t value, Tox_Group_Mod_Event *out) +static bool tox_group_mod_event_from_int(uint32_t value, Tox_Group_Mod_Event *out_enum) { switch (value) { case TOX_GROUP_MOD_EVENT_KICK: { - *out = TOX_GROUP_MOD_EVENT_KICK; + *out_enum = TOX_GROUP_MOD_EVENT_KICK; return true; } case TOX_GROUP_MOD_EVENT_OBSERVER: { - *out = TOX_GROUP_MOD_EVENT_OBSERVER; + *out_enum = TOX_GROUP_MOD_EVENT_OBSERVER; return true; } case TOX_GROUP_MOD_EVENT_USER: { - *out = TOX_GROUP_MOD_EVENT_USER; + *out_enum = TOX_GROUP_MOD_EVENT_USER; return true; } case TOX_GROUP_MOD_EVENT_MODERATOR: { - *out = TOX_GROUP_MOD_EVENT_MODERATOR; + *out_enum = TOX_GROUP_MOD_EVENT_MODERATOR; return true; } default: { - *out = TOX_GROUP_MOD_EVENT_KICK; + *out_enum = TOX_GROUP_MOD_EVENT_KICK; return false; } } @@ -305,35 +305,35 @@ bool tox_group_mod_event_unpack(Tox_Group_Mod_Event *val, Bin_Unpack *bu) } non_null() -static bool tox_group_exit_type_from_int(uint32_t value, Tox_Group_Exit_Type *out) +static bool tox_group_exit_type_from_int(uint32_t value, Tox_Group_Exit_Type *out_enum) { switch (value) { case TOX_GROUP_EXIT_TYPE_QUIT: { - *out = TOX_GROUP_EXIT_TYPE_QUIT; + *out_enum = TOX_GROUP_EXIT_TYPE_QUIT; return true; } case TOX_GROUP_EXIT_TYPE_TIMEOUT: { - *out = TOX_GROUP_EXIT_TYPE_TIMEOUT; + *out_enum = TOX_GROUP_EXIT_TYPE_TIMEOUT; return true; } case TOX_GROUP_EXIT_TYPE_DISCONNECTED: { - *out = TOX_GROUP_EXIT_TYPE_DISCONNECTED; + *out_enum = TOX_GROUP_EXIT_TYPE_DISCONNECTED; return true; } case TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED: { - *out = TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED; + *out_enum = TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED; return true; } case TOX_GROUP_EXIT_TYPE_KICK: { - *out = TOX_GROUP_EXIT_TYPE_KICK; + *out_enum = TOX_GROUP_EXIT_TYPE_KICK; return true; } case TOX_GROUP_EXIT_TYPE_SYNC_ERROR: { - *out = TOX_GROUP_EXIT_TYPE_SYNC_ERROR; + *out_enum = TOX_GROUP_EXIT_TYPE_SYNC_ERROR; return true; } default: { - *out = TOX_GROUP_EXIT_TYPE_QUIT; + *out_enum = TOX_GROUP_EXIT_TYPE_QUIT; return false; } } diff --git a/toxcore/util.c b/toxcore/util.c index 1851e58a08..85d29a44cd 100644 --- a/toxcore/util.c +++ b/toxcore/util.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013 Tox project. * Copyright © 2013 plutooo */ @@ -16,6 +16,7 @@ #include #include +#include "attributes.h" #include "ccompat.h" #include "mem.h" diff --git a/toxcore/util_test.cc b/toxcore/util_test.cc index 94e653f218..ccdd9795da 100644 --- a/toxcore/util_test.cc +++ b/toxcore/util_test.cc @@ -1,39 +1,14 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2024 The TokTok team. + */ #include "util.h" #include -#include "crypto_core.h" -#include "crypto_core_test_util.hh" +#include namespace { -TEST(Util, TwoRandomIdsAreNotEqual) -{ - Test_Random rng; - 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]; - - crypto_new_keypair(rng, pk1, sk1); - crypto_new_keypair(rng, pk2, sk2); - - EXPECT_FALSE(pk_equal(pk1, pk2)); -} - -TEST(Util, IdCopyMakesKeysEqual) -{ - Test_Random rng; - uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; - uint8_t sk1[CRYPTO_SECRET_KEY_SIZE]; - uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE] = {0}; - - crypto_new_keypair(rng, pk1, sk1); - pk_copy(pk2, pk1); - - EXPECT_TRUE(pk_equal(pk1, pk2)); -} - TEST(Cmp, OrdersNumbersCorrectly) { EXPECT_EQ(cmp_uint(1, 2), -1); diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c index c43e357528..4e43b17f76 100644 --- a/toxencryptsave/toxencryptsave.c +++ b/toxencryptsave/toxencryptsave.c @@ -67,7 +67,8 @@ void tox_pass_key_free(Tox_Pass_Key *key) * produce the same key as was previously used. Any data encrypted with this * module can be used as input. * - * The cipher text must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * The cipher text must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in + * length. * The salt must be TOX_PASS_SALT_LENGTH bytes in length. * If the passed byte arrays are smaller than required, the behaviour is * undefined. @@ -182,10 +183,11 @@ Tox_Pass_Key *tox_pass_key_derive_with_salt( } /** - * Encrypt a plain text with a key produced by tox_pass_key_derive or tox_pass_key_derive_with_salt. + * Encrypt a plain text with a key produced by tox_pass_key_derive or + * tox_pass_key_derive_with_salt. * - * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. + * The output array must be at least + * `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. * * @param plaintext A byte array of length `plaintext_len`. * @param plaintext_len The length of the plain text array. Bigger than 0. @@ -229,8 +231,8 @@ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t plaintext[], si ciphertext += crypto_box_NONCEBYTES; /* now encrypt */ - if (encrypt_data_symmetric(key->key, nonce, plaintext, plaintext_len, ciphertext) - != plaintext_len + crypto_box_MACBYTES) { + const int32_t encrypted_len = encrypt_data_symmetric(os_memory(), key->key, nonce, plaintext, plaintext_len, ciphertext); + if (encrypted_len < 0 || (size_t)encrypted_len != plaintext_len + crypto_box_MACBYTES) { SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); return false; } @@ -242,9 +244,9 @@ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t plaintext[], si /** * Encrypts the given data with the given passphrase. * - * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. This delegates to tox_pass_key_derive and - * tox_pass_key_encrypt. + * The output array must be at least + * `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. This delegates + * to tox_pass_key_derive and tox_pass_key_encrypt. * * @param plaintext A byte array of length `plaintext_len`. * @param plaintext_len The length of the plain text array. Bigger than 0. @@ -280,7 +282,8 @@ bool tox_pass_encrypt(const uint8_t plaintext[], size_t plaintext_len, const uin * tox_pass_key_derive or tox_pass_key_derive_with_salt. * * @param ciphertext A byte array of length `ciphertext_len`. - * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param ciphertext_len The length of the cipher text array. At least + * TOX_PASS_ENCRYPTION_EXTRA_LENGTH. * @param plaintext The plain text array to write the decrypted data to. * * @return true on success. @@ -313,8 +316,8 @@ bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t ciphertext[], s ciphertext += crypto_box_NONCEBYTES; /* decrypt the ciphertext */ - if (decrypt_data_symmetric(key->key, nonce, ciphertext, decrypt_length + crypto_box_MACBYTES, plaintext) - != decrypt_length) { + const int32_t decrypted_len = decrypt_data_symmetric(os_memory(), key->key, nonce, ciphertext, decrypt_length + crypto_box_MACBYTES, plaintext); + if (decrypted_len < 0 || (size_t)decrypted_len != decrypt_length) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); return false; } @@ -326,11 +329,13 @@ bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t ciphertext[], s /** * Decrypts the given data with the given passphrase. * - * The output array must be at least `ciphertext_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. This delegates to tox_pass_key_decrypt. + * The output array must be at least + * `ciphertext_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. This + * delegates to tox_pass_key_decrypt. * * @param ciphertext A byte array of length `ciphertext_len`. - * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param ciphertext_len The length of the cipher text array. At least + * TOX_PASS_ENCRYPTION_EXTRA_LENGTH. * @param passphrase The user-provided password. Can be empty. * @param passphrase_len The length of the password. * @param plaintext The plain text array to write the decrypted data to. diff --git a/toxencryptsave/toxencryptsave.h b/toxencryptsave/toxencryptsave.h index b9691551c7..e4cf116c97 100644 --- a/toxencryptsave/toxencryptsave.h +++ b/toxencryptsave/toxencryptsave.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2016-2018 The TokTok team. + * Copyright © 2016-2024 The TokTok team. * Copyright © 2013-2016 Tox Developers. */ @@ -165,9 +165,9 @@ typedef enum Tox_Err_Decryption { /** * Encrypts the given data with the given passphrase. * - * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. This delegates to tox_pass_key_derive and - * tox_pass_key_encrypt. + * The output array must be at least + * `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. This delegates + * to tox_pass_key_derive and tox_pass_key_encrypt. * * @param plaintext A byte array of length `plaintext_len`. * @param plaintext_len The length of the plain text array. Bigger than 0. @@ -183,11 +183,13 @@ bool tox_pass_encrypt(const uint8_t plaintext[], size_t plaintext_len, const uin /** * Decrypts the given data with the given passphrase. * - * The output array must be at least `ciphertext_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. This delegates to tox_pass_key_decrypt. + * The output array must be at least + * `ciphertext_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. This + * delegates to tox_pass_key_decrypt. * * @param ciphertext A byte array of length `ciphertext_len`. - * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param ciphertext_len The length of the cipher text array. At least + * TOX_PASS_ENCRYPTION_EXTRA_LENGTH. * @param passphrase The user-provided password. Can be empty. * @param passphrase_len The length of the password. * @param plaintext The plain text array to write the decrypted data to. @@ -215,7 +217,8 @@ bool tox_pass_decrypt(const uint8_t ciphertext[], size_t ciphertext_len, const u * user-provided password. * * The Tox_Pass_Key structure is hidden in the implementation. It can be created - * using tox_pass_key_derive or tox_pass_key_derive_with_salt and must be deallocated using tox_pass_key_free. + * using tox_pass_key_derive or tox_pass_key_derive_with_salt and must be + * deallocated using tox_pass_key_free. */ #ifndef TOX_PASS_KEY_DEFINED #define TOX_PASS_KEY_DEFINED @@ -261,10 +264,11 @@ Tox_Pass_Key *tox_pass_key_derive_with_salt( const uint8_t salt[TOX_PASS_SALT_LENGTH], Tox_Err_Key_Derivation *error); /** - * Encrypt a plain text with a key produced by tox_pass_key_derive or tox_pass_key_derive_with_salt. + * Encrypt a plain text with a key produced by tox_pass_key_derive or + * tox_pass_key_derive_with_salt. * - * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` - * bytes long. + * The output array must be at least + * `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` bytes long. * * @param plaintext A byte array of length `plaintext_len`. * @param plaintext_len The length of the plain text array. Bigger than 0. @@ -280,7 +284,8 @@ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t plaintext[], si * tox_pass_key_derive or tox_pass_key_derive_with_salt. * * @param ciphertext A byte array of length `ciphertext_len`. - * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param ciphertext_len The length of the cipher text array. At least + * TOX_PASS_ENCRYPTION_EXTRA_LENGTH. * @param plaintext The plain text array to write the decrypted data to. * * @return true on success. @@ -315,7 +320,8 @@ typedef enum Tox_Err_Get_Salt { * produce the same key as was previously used. Any data encrypted with this * module can be used as input. * - * The cipher text must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * The cipher text must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in + * length. * The salt must be TOX_PASS_SALT_LENGTH bytes in length. * If the passed byte arrays are smaller than required, the behaviour is * undefined.