Merge commit '227425b90e9a671118026689dd30967e127a1090' as 'external/toxcore/c-toxcore'
This commit is contained in:
840
external/toxcore/c-toxcore/toxcore/BUILD.bazel
vendored
Normal file
840
external/toxcore/c-toxcore/toxcore/BUILD.bazel
vendored
Normal file
@ -0,0 +1,840 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
|
||||
load("//tools:no_undefined.bzl", "cc_library")
|
||||
|
||||
package(features = ["layering_check"])
|
||||
|
||||
exports_files(
|
||||
srcs = ["tox.h"],
|
||||
visibility = ["//c-toxcore:__pkg__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "attributes",
|
||||
hdrs = ["attributes.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ccompat",
|
||||
srcs = ["ccompat.c"],
|
||||
hdrs = ["ccompat.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [":attributes"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "util",
|
||||
srcs = ["util.c"],
|
||||
hdrs = ["util.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing/fuzzing:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":attributes",
|
||||
":ccompat",
|
||||
"@pthread",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "util_test",
|
||||
size = "small",
|
||||
srcs = ["util_test.cc"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bin_pack",
|
||||
srcs = ["bin_pack.c"],
|
||||
hdrs = ["bin_pack.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
"//c-toxcore/third_party:cmp",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bin_unpack",
|
||||
srcs = ["bin_unpack.c"],
|
||||
hdrs = ["bin_unpack.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
"//c-toxcore/third_party:cmp",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bin_pack_test",
|
||||
size = "small",
|
||||
srcs = ["bin_pack_test.cc"],
|
||||
deps = [
|
||||
":bin_pack",
|
||||
":bin_unpack",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "crypto_core",
|
||||
srcs = ["crypto_core.c"],
|
||||
hdrs = ["crypto_core.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
"@libsodium",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "crypto_core_test",
|
||||
size = "small",
|
||||
srcs = ["crypto_core_test.cc"],
|
||||
flaky = True,
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "list",
|
||||
srcs = ["list.c"],
|
||||
hdrs = ["list.h"],
|
||||
deps = [":ccompat"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "list_test",
|
||||
size = "small",
|
||||
srcs = ["list_test.cc"],
|
||||
deps = [
|
||||
":list",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "logger",
|
||||
srcs = ["logger.c"],
|
||||
hdrs = ["logger.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [":ccompat"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "state",
|
||||
srcs = ["state.c"],
|
||||
hdrs = ["state.h"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":logger",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "mono_time",
|
||||
srcs = ["mono_time.c"],
|
||||
hdrs = ["mono_time.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
"@pthread",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "mono_time_test",
|
||||
size = "small",
|
||||
srcs = ["mono_time_test.cc"],
|
||||
deps = [
|
||||
":mono_time",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "shared_key_cache",
|
||||
srcs = ["shared_key_cache.c"],
|
||||
hdrs = ["shared_key_cache.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":mono_time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "network",
|
||||
srcs = ["network.c"],
|
||||
hdrs = ["network.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing/fuzzing:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":logger",
|
||||
":mono_time",
|
||||
":util",
|
||||
"@libsodium",
|
||||
"@psocket",
|
||||
"@pthread",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "network_test",
|
||||
size = "small",
|
||||
srcs = ["network_test.cc"],
|
||||
deps = [
|
||||
":network",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "timed_auth",
|
||||
srcs = ["timed_auth.c"],
|
||||
hdrs = ["timed_auth.h"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":mono_time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ping_array",
|
||||
srcs = ["ping_array.c"],
|
||||
hdrs = ["ping_array.h"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":mono_time",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "ping_array_test",
|
||||
size = "small",
|
||||
srcs = ["ping_array_test.cc"],
|
||||
deps = [
|
||||
":mono_time",
|
||||
":ping_array",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "LAN_discovery",
|
||||
srcs = ["LAN_discovery.c"],
|
||||
hdrs = ["LAN_discovery.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":network",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "DHT",
|
||||
srcs = [
|
||||
"DHT.c",
|
||||
"ping.c",
|
||||
],
|
||||
hdrs = [
|
||||
"DHT.h",
|
||||
"ping.h",
|
||||
],
|
||||
visibility = [
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":LAN_discovery",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":logger",
|
||||
":mono_time",
|
||||
":network",
|
||||
":ping_array",
|
||||
":shared_key_cache",
|
||||
":state",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "DHT_test",
|
||||
size = "small",
|
||||
srcs = ["DHT_test.cc"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":crypto_core",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "DHT_fuzz_test",
|
||||
srcs = ["DHT_fuzz_test.cc"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"],
|
||||
deps = [
|
||||
":DHT",
|
||||
"//c-toxcore/testing/fuzzing:fuzz_support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "onion",
|
||||
srcs = ["onion.c"],
|
||||
hdrs = ["onion.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":mono_time",
|
||||
":shared_key_cache",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "forwarding",
|
||||
srcs = ["forwarding.c"],
|
||||
hdrs = ["forwarding.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":ccompat",
|
||||
":network",
|
||||
":timed_auth",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "forwarding_fuzz_test",
|
||||
srcs = ["forwarding_fuzz_test.cc"],
|
||||
#corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
|
||||
deps = [
|
||||
":forwarding",
|
||||
"//c-toxcore/testing/fuzzing:fuzz_support",
|
||||
"//c-toxcore/testing/fuzzing:fuzz_tox",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "announce",
|
||||
srcs = ["announce.c"],
|
||||
hdrs = ["announce.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":LAN_discovery",
|
||||
":ccompat",
|
||||
":forwarding",
|
||||
":shared_key_cache",
|
||||
":timed_auth",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "TCP_common",
|
||||
srcs = ["TCP_common.c"],
|
||||
hdrs = ["TCP_common.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":network",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "TCP_server",
|
||||
srcs = ["TCP_server.c"],
|
||||
hdrs = ["TCP_server.h"],
|
||||
copts = select({
|
||||
"//tools/config:linux": ["-DTCP_SERVER_USE_EPOLL=1"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":TCP_common",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":forwarding",
|
||||
":list",
|
||||
":mono_time",
|
||||
":onion",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "TCP_client",
|
||||
srcs = ["TCP_client.c"],
|
||||
hdrs = ["TCP_client.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":TCP_common",
|
||||
":ccompat",
|
||||
":forwarding",
|
||||
":mono_time",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "TCP_connection",
|
||||
srcs = ["TCP_connection.c"],
|
||||
hdrs = ["TCP_connection.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":TCP_client",
|
||||
":TCP_common",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":list",
|
||||
":mono_time",
|
||||
":onion",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "TCP_connection_test",
|
||||
size = "small",
|
||||
srcs = ["TCP_connection_test.cc"],
|
||||
deps = [
|
||||
":TCP_connection",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "net_crypto",
|
||||
srcs = ["net_crypto.c"],
|
||||
hdrs = ["net_crypto.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":TCP_connection",
|
||||
":ccompat",
|
||||
":list",
|
||||
":mono_time",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "onion_announce",
|
||||
srcs = ["onion_announce.c"],
|
||||
hdrs = ["onion_announce.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":DHT",
|
||||
":LAN_discovery",
|
||||
":ccompat",
|
||||
":mono_time",
|
||||
":onion",
|
||||
":shared_key_cache",
|
||||
":timed_auth",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "group_announce",
|
||||
srcs = ["group_announce.c"],
|
||||
hdrs = ["group_announce.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":DHT",
|
||||
":LAN_discovery",
|
||||
":ccompat",
|
||||
":mono_time",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "group_announce_test",
|
||||
size = "small",
|
||||
srcs = ["group_announce_test.cc"],
|
||||
deps = [
|
||||
":group_announce",
|
||||
":mono_time",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "group_onion_announce",
|
||||
srcs = ["group_onion_announce.c"],
|
||||
hdrs = ["group_onion_announce.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":group_announce",
|
||||
":onion_announce",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "group_announce_fuzz_test",
|
||||
srcs = ["group_announce_fuzz_test.cc"],
|
||||
#corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
|
||||
deps = [
|
||||
":group_announce",
|
||||
"//c-toxcore/testing/fuzzing:fuzz_support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "onion_client",
|
||||
srcs = ["onion_client.c"],
|
||||
hdrs = ["onion_client.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":LAN_discovery",
|
||||
":ccompat",
|
||||
":group_onion_announce",
|
||||
":mono_time",
|
||||
":net_crypto",
|
||||
":network",
|
||||
":onion_announce",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "friend_connection",
|
||||
srcs = ["friend_connection.c"],
|
||||
hdrs = ["friend_connection.h"],
|
||||
visibility = ["//c-toxcore/auto_tests:__pkg__"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":ccompat",
|
||||
":mono_time",
|
||||
":net_crypto",
|
||||
":onion_client",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "friend_connection_test",
|
||||
size = "small",
|
||||
srcs = ["friend_connection_test.cc"],
|
||||
deps = [
|
||||
":friend_connection",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "friend_requests",
|
||||
srcs = ["friend_requests.c"],
|
||||
hdrs = ["friend_requests.h"],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":friend_connection",
|
||||
":network",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "group_moderation",
|
||||
srcs = ["group_moderation.c"],
|
||||
hdrs = ["group_moderation.h"],
|
||||
deps = [
|
||||
":DHT",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":logger",
|
||||
":mono_time",
|
||||
":network",
|
||||
":util",
|
||||
"@libsodium",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "group_moderation_test",
|
||||
size = "small",
|
||||
srcs = ["group_moderation_test.cc"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":group_moderation",
|
||||
":logger",
|
||||
":util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "group_moderation_fuzz_test",
|
||||
srcs = ["group_moderation_fuzz_test.cc"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
|
||||
deps = [
|
||||
":group_moderation",
|
||||
"//c-toxcore/testing/fuzzing:fuzz_support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "Messenger",
|
||||
srcs = [
|
||||
"Messenger.c",
|
||||
"group_chats.c",
|
||||
"group_connection.c",
|
||||
"group_pack.c",
|
||||
],
|
||||
hdrs = [
|
||||
"Messenger.h",
|
||||
"group_chats.h",
|
||||
"group_common.h",
|
||||
"group_connection.h",
|
||||
"group_pack.h",
|
||||
],
|
||||
visibility = [
|
||||
"//c-toxcore/auto_tests:__pkg__",
|
||||
"//c-toxcore/other:__pkg__",
|
||||
"//c-toxcore/testing:__pkg__",
|
||||
"//c-toxcore/toxav:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":DHT",
|
||||
":LAN_discovery",
|
||||
":TCP_connection",
|
||||
":TCP_server",
|
||||
":announce",
|
||||
":bin_pack",
|
||||
":bin_unpack",
|
||||
":ccompat",
|
||||
":crypto_core",
|
||||
":forwarding",
|
||||
":friend_connection",
|
||||
":friend_requests",
|
||||
":group_moderation",
|
||||
":group_onion_announce",
|
||||
":logger",
|
||||
":mono_time",
|
||||
":net_crypto",
|
||||
":network",
|
||||
":onion_announce",
|
||||
":state",
|
||||
":util",
|
||||
"@libsodium",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "group",
|
||||
srcs = ["group.c"],
|
||||
hdrs = ["group.h"],
|
||||
visibility = ["//c-toxcore/toxav:__pkg__"],
|
||||
deps = [
|
||||
":Messenger",
|
||||
":ccompat",
|
||||
":mono_time",
|
||||
":state",
|
||||
":util",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tox",
|
||||
srcs = [
|
||||
"tox.c",
|
||||
"tox_api.c",
|
||||
"tox_private.c",
|
||||
],
|
||||
hdrs = [
|
||||
"tox.h",
|
||||
"tox_private.h",
|
||||
"tox_struct.h",
|
||||
],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":Messenger",
|
||||
":ccompat",
|
||||
":group",
|
||||
":group_moderation",
|
||||
":logger",
|
||||
":mono_time",
|
||||
":network",
|
||||
"//c-toxcore/toxencryptsave:defines",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "tox_test",
|
||||
size = "small",
|
||||
srcs = ["tox_test.cc"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":tox",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tox_unpack",
|
||||
srcs = ["tox_unpack.c"],
|
||||
hdrs = ["tox_unpack.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":bin_unpack",
|
||||
":ccompat",
|
||||
":tox",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tox_events",
|
||||
srcs = ["tox_events.c"] + glob([
|
||||
"events/*.c",
|
||||
"events/*.h",
|
||||
]),
|
||||
hdrs = ["tox_events.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":bin_pack",
|
||||
":bin_unpack",
|
||||
":ccompat",
|
||||
":tox",
|
||||
":tox_unpack",
|
||||
"//c-toxcore/third_party:cmp",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "tox_events_test",
|
||||
size = "small",
|
||||
srcs = ["tox_events_test.cc"],
|
||||
deps = [
|
||||
":crypto_core",
|
||||
":tox_events",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "tox_events_fuzz_test",
|
||||
srcs = ["tox_events_fuzz_test.cc"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:tox_events_fuzz_test"],
|
||||
deps = [":tox_events"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tox_dispatch",
|
||||
srcs = ["tox_dispatch.c"],
|
||||
hdrs = ["tox_dispatch.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
":ccompat",
|
||||
":tox_events",
|
||||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "toxcore",
|
||||
actual = ":tox_dispatch",
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
)
|
||||
|
||||
sh_library(
|
||||
name = "cimple_files",
|
||||
srcs = glob([
|
||||
"events/*.c",
|
||||
"events/*.h",
|
||||
"*.c",
|
||||
"*.h",
|
||||
]),
|
||||
visibility = ["//c-toxcore/testing:__pkg__"],
|
||||
)
|
3113
external/toxcore/c-toxcore/toxcore/DHT.c
vendored
Normal file
3113
external/toxcore/c-toxcore/toxcore/DHT.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
542
external/toxcore/c-toxcore/toxcore/DHT.h
vendored
Normal file
542
external/toxcore/c-toxcore/toxcore/DHT.h
vendored
Normal file
@ -0,0 +1,542 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief An implementation of the DHT as seen in docs/updates/DHT.md
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_DHT_H
|
||||
#define C_TOXCORE_TOXCORE_DHT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "attributes.h"
|
||||
#include "crypto_core.h"
|
||||
#include "logger.h"
|
||||
#include "mono_time.h"
|
||||
#include "network.h"
|
||||
#include "ping_array.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Encryption and signature keys definition */
|
||||
#define ENC_PUBLIC_KEY_SIZE CRYPTO_PUBLIC_KEY_SIZE
|
||||
#define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE
|
||||
#define SIG_PUBLIC_KEY_SIZE CRYPTO_SIGN_PUBLIC_KEY_SIZE
|
||||
#define SIG_SECRET_KEY_SIZE CRYPTO_SIGN_SECRET_KEY_SIZE
|
||||
|
||||
/* Size of the group chat_id */
|
||||
#define CHAT_ID_SIZE SIG_PUBLIC_KEY_SIZE
|
||||
|
||||
/* Extended keys for group chats */
|
||||
#define EXT_SECRET_KEY_SIZE (ENC_SECRET_KEY_SIZE + SIG_SECRET_KEY_SIZE)
|
||||
#define EXT_PUBLIC_KEY_SIZE (ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE)
|
||||
|
||||
|
||||
/* Maximum size of a signature (may be smaller) */
|
||||
#define SIGNATURE_SIZE CRYPTO_SIGNATURE_SIZE
|
||||
/** Maximum number of clients stored per friend. */
|
||||
#define MAX_FRIEND_CLIENTS 8
|
||||
|
||||
#define LCLIENT_NODES MAX_FRIEND_CLIENTS
|
||||
#define LCLIENT_LENGTH 128
|
||||
|
||||
/** A list of the clients mathematically closest to ours. */
|
||||
#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES)
|
||||
|
||||
#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8
|
||||
|
||||
/** The max number of nodes to send with send nodes. */
|
||||
#define MAX_SENT_NODES 4
|
||||
|
||||
/** Ping timeout in seconds */
|
||||
#define PING_TIMEOUT 5
|
||||
|
||||
/** size of DHT ping arrays. */
|
||||
#define DHT_PING_ARRAY_SIZE 512
|
||||
|
||||
/** Ping interval in seconds for each node in our lists. */
|
||||
#define PING_INTERVAL 60
|
||||
|
||||
/** The number of seconds for a non responsive node to become bad. */
|
||||
#define PINGS_MISSED_NODE_GOES_BAD 1
|
||||
#define PING_ROUNDTRIP 2
|
||||
#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP))
|
||||
|
||||
/**
|
||||
* The number of "fake" friends to add.
|
||||
*
|
||||
* (for optimization purposes and so our paths for the onion part are more random)
|
||||
*/
|
||||
#define DHT_FAKE_FRIEND_NUMBER 2
|
||||
|
||||
/** Maximum packet size for a DHT request packet. */
|
||||
#define MAX_CRYPTO_REQUEST_SIZE 1024
|
||||
|
||||
#define CRYPTO_PACKET_FRIEND_REQ 32 // Friend request crypto packet ID.
|
||||
#define CRYPTO_PACKET_DHTPK 156
|
||||
#define CRYPTO_PACKET_NAT_PING 254 // NAT ping crypto packet ID.
|
||||
|
||||
/* Max size of a packed node for IPV4 and IPV6 respectively */
|
||||
#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
|
||||
#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* This define can eventually be removed; it is necessary if a significant
|
||||
* proportion of dht nodes do not implement the dht announcements protocol.
|
||||
*/
|
||||
#define CHECK_ANNOUNCE_NODE
|
||||
|
||||
/**
|
||||
* @brief Create a request to peer.
|
||||
*
|
||||
* Packs the data and sender public key and encrypts the packet.
|
||||
*
|
||||
* @param[in] send_public_key public key of the sender.
|
||||
* @param[in] send_secret_key secret key of the sender.
|
||||
* @param[out] packet an array of @ref MAX_CRYPTO_REQUEST_SIZE big.
|
||||
* @param[in] recv_public_key public key of the receiver.
|
||||
* @param[in] data represents the data we send with the request.
|
||||
* @param[in] data_length the length of the data.
|
||||
* @param[in] request_id the id of the request (32 = friend request, 254 = ping request).
|
||||
*
|
||||
* @attention Constraints:
|
||||
* @code
|
||||
* sizeof(packet) >= MAX_CRYPTO_REQUEST_SIZE
|
||||
* @endcode
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @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,
|
||||
uint8_t *packet, const uint8_t *recv_public_key,
|
||||
const uint8_t *data, uint32_t data_length, uint8_t request_id);
|
||||
|
||||
/**
|
||||
* @brief Decrypts and unpacks a DHT request packet.
|
||||
*
|
||||
* Puts the senders public key in the request in @p public_key, the data from
|
||||
* the request in @p data.
|
||||
*
|
||||
* @param[in] self_public_key public key of the receiver (us).
|
||||
* @param[in] self_secret_key secret key of the receiver (us).
|
||||
* @param[out] public_key public key of the sender, copied from the input packet.
|
||||
* @param[out] data decrypted request data, copied from the input packet, must
|
||||
* have room for @ref MAX_CRYPTO_REQUEST_SIZE bytes.
|
||||
* @param[in] packet is the request packet.
|
||||
* @param[in] packet_length length of the packet.
|
||||
*
|
||||
* @attention Constraints:
|
||||
* @code
|
||||
* sizeof(data) >= MAX_CRYPTO_REQUEST_SIZE
|
||||
* @endcode
|
||||
*
|
||||
* @retval -1 if not valid request.
|
||||
* @return the length of the unpacked data.
|
||||
*/
|
||||
non_null()
|
||||
int handle_request(
|
||||
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 {
|
||||
IP_Port ip_port;
|
||||
uint64_t timestamp;
|
||||
} IPPTs;
|
||||
|
||||
typedef struct IPPTsPng {
|
||||
IP_Port ip_port;
|
||||
uint64_t timestamp;
|
||||
uint64_t last_pinged;
|
||||
|
||||
/* Returned by this node */
|
||||
IP_Port ret_ip_port;
|
||||
uint64_t ret_timestamp;
|
||||
/* true if this ip_port is ours */
|
||||
bool ret_ip_self;
|
||||
} IPPTsPng;
|
||||
|
||||
typedef struct Client_data {
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
IPPTsPng assoc4;
|
||||
IPPTsPng assoc6;
|
||||
|
||||
#ifdef CHECK_ANNOUNCE_NODE
|
||||
/* Responded to data search? */
|
||||
bool announce_node;
|
||||
#endif
|
||||
} Client_data;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct NAT {
|
||||
/* true if currently hole punching */
|
||||
bool hole_punching;
|
||||
uint32_t punching_index;
|
||||
uint32_t tries;
|
||||
uint32_t punching_index2;
|
||||
|
||||
uint64_t punching_timestamp;
|
||||
uint64_t recv_nat_ping_timestamp;
|
||||
uint64_t nat_ping_id;
|
||||
uint64_t nat_ping_timestamp;
|
||||
} NAT;
|
||||
|
||||
typedef struct Node_format {
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
IP_Port ip_port;
|
||||
} Node_format;
|
||||
|
||||
extern const Node_format empty_node_format;
|
||||
|
||||
typedef struct DHT_Friend DHT_Friend;
|
||||
|
||||
non_null() const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend);
|
||||
non_null() const Client_data *dht_friend_client(const DHT_Friend *dht_friend, size_t index);
|
||||
|
||||
/** @return packet size of packed node with ip_family on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int packed_node_size(Family ip_family);
|
||||
|
||||
/** @brief Pack an IP_Port structure into data of max size length.
|
||||
*
|
||||
* Packed_length is the offset of data currently packed.
|
||||
*
|
||||
* @return size of packed IP_Port data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port);
|
||||
|
||||
/** @brief Encrypt plain and write resulting DHT packet into packet with max size length.
|
||||
*
|
||||
* @return size of packet on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int dht_create_packet(const Random *rng,
|
||||
const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
|
||||
const uint8_t *shared_key, const uint8_t type,
|
||||
const uint8_t *plain, size_t plain_length,
|
||||
uint8_t *packet, size_t length);
|
||||
|
||||
/** @brief Unpack IP_Port structure from data of max size length into ip_port.
|
||||
*
|
||||
* len_processed is the offset of data currently unpacked.
|
||||
*
|
||||
* @return size of unpacked ip_port on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled);
|
||||
|
||||
/** @brief Pack number of nodes into data of maxlength length.
|
||||
*
|
||||
* @return length of packed nodes on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int pack_nodes(const Logger *logger, uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number);
|
||||
|
||||
/** @brief Unpack data of length into nodes of size max_num_nodes.
|
||||
* Put the length of the data processed in processed_data_len.
|
||||
* tcp_enabled sets if TCP nodes are expected (true) or not (false).
|
||||
*
|
||||
* @return number of unpacked nodes on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1, 4) nullable(3)
|
||||
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
|
||||
uint16_t length, bool tcp_enabled);
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
typedef int cryptopacket_handler_cb(void *object, const IP_Port *ip_port, const uint8_t *source_pubkey,
|
||||
const uint8_t *data, uint16_t len, void *userdata);
|
||||
|
||||
typedef struct DHT DHT;
|
||||
|
||||
non_null() const uint8_t *dht_get_self_public_key(const DHT *dht);
|
||||
non_null() const uint8_t *dht_get_self_secret_key(const DHT *dht);
|
||||
non_null() void dht_set_self_public_key(DHT *dht, const uint8_t *key);
|
||||
non_null() void dht_set_self_secret_key(DHT *dht, const uint8_t *key);
|
||||
|
||||
non_null() Networking_Core *dht_get_net(const DHT *dht);
|
||||
non_null() struct Ping *dht_get_ping(const DHT *dht);
|
||||
non_null() const Client_data *dht_get_close_clientlist(const DHT *dht);
|
||||
non_null() const Client_data *dht_get_close_client(const DHT *dht, uint32_t client_num);
|
||||
non_null() uint16_t dht_get_num_friends(const DHT *dht);
|
||||
|
||||
non_null() DHT_Friend *dht_get_friend(DHT *dht, uint32_t friend_num);
|
||||
non_null() const uint8_t *dht_get_friend_public_key(const DHT *dht, uint32_t friend_num);
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||
* for packets that we receive.
|
||||
*/
|
||||
non_null()
|
||||
const uint8_t *dht_get_shared_key_recv(DHT *dht, const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||
* for packets that we send.
|
||||
*/
|
||||
non_null()
|
||||
const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* Sends a getnodes request to `ip_port` with the public key `public_key` for nodes
|
||||
* that are close to `client_id`.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id);
|
||||
|
||||
typedef void dht_ip_cb(void *object, int32_t number, const IP_Port *ip_port);
|
||||
|
||||
typedef void dht_get_nodes_response_cb(const DHT *dht, const Node_format *node, void *user_data);
|
||||
|
||||
/** Sets the callback to be triggered on a getnodes response. */
|
||||
non_null(1) nullable(2)
|
||||
void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function);
|
||||
|
||||
/** @brief Add a new friend to the friends list.
|
||||
* @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
*
|
||||
* @param ip_callback is the callback of a function that will be called when the ip address
|
||||
* is found along with arguments data and number.
|
||||
* @param data User data for the callback
|
||||
* @param number Will be passed to ip_callback
|
||||
*
|
||||
* @param lock_token will be set to a non zero number that must be passed to `dht_delfriend()`
|
||||
* to properly remove the callback.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure (friends list is full).
|
||||
*/
|
||||
non_null(1, 2, 6) nullable(3, 4)
|
||||
int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
|
||||
void *data, int32_t number, uint32_t *lock_token);
|
||||
|
||||
/** @brief Delete a friend from the friends list.
|
||||
* public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
* @param dht The DHT object
|
||||
* @param public_key The public key of the friend
|
||||
* @param lock_token The token received by dht_addfriend(...)
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure (public_key not in friends list).
|
||||
*/
|
||||
non_null()
|
||||
int dht_delfriend(DHT *dht, const uint8_t *public_key, uint32_t lock_token);
|
||||
|
||||
/** @brief Get ip of friend.
|
||||
*
|
||||
* @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
*
|
||||
* @retval -1 if public_key does NOT refer to a friend
|
||||
* @retval 0 if public_key refers to a friend and we failed to find the friend (yet)
|
||||
* @retval 1 if public_key refers to a friend and we found him
|
||||
*/
|
||||
non_null()
|
||||
int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port);
|
||||
|
||||
/** @brief Compares pk1 and pk2 with pk.
|
||||
*
|
||||
* @retval 0 if both are same distance.
|
||||
* @retval 1 if pk1 is closer.
|
||||
* @retval 2 if pk2 is closer.
|
||||
*/
|
||||
non_null()
|
||||
int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2);
|
||||
|
||||
/** Return index of first unequal bit number between public keys pk1 and pk2. */
|
||||
non_null()
|
||||
unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2);
|
||||
|
||||
/**
|
||||
* Add node to the node list making sure only the nodes closest to cmp_pk are in the list.
|
||||
*
|
||||
* @return true iff the node was added to the list.
|
||||
*/
|
||||
non_null()
|
||||
bool add_to_list(
|
||||
Node_format *nodes_list, uint32_t length, const uint8_t *pk, const IP_Port *ip_port, const uint8_t *cmp_pk);
|
||||
|
||||
/** Return 1 if node can be added to close list, 0 if it can't. */
|
||||
non_null()
|
||||
bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port);
|
||||
|
||||
#ifdef CHECK_ANNOUNCE_NODE
|
||||
/** Set node as announce node. */
|
||||
non_null()
|
||||
void set_announce_node(DHT *dht, const uint8_t *public_key);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know
|
||||
* and put them in nodes_list (must be MAX_SENT_NODES big).
|
||||
*
|
||||
* sa_family = family (IPv4 or IPv6) (0 if we don't care)?
|
||||
* is_LAN = return some LAN ips (true or false)
|
||||
* want_announce: return only nodes which implement the dht announcements protocol.
|
||||
*
|
||||
* @return the number of nodes returned.
|
||||
*/
|
||||
non_null()
|
||||
int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family,
|
||||
bool is_LAN, bool want_announce);
|
||||
|
||||
|
||||
/** @brief Put up to max_num nodes in nodes from the random friends.
|
||||
*
|
||||
* Important: this function relies on the first two DHT friends *not* being real
|
||||
* friends to avoid leaking information about real friends into the onion paths.
|
||||
*
|
||||
* @return the number of nodes.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t randfriends_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num);
|
||||
|
||||
/** @brief Put up to max_num nodes in nodes from the closelist.
|
||||
*
|
||||
* @return the number of nodes.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t closelist_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num);
|
||||
|
||||
/** Run this function at least a couple times per second (It's the main loop). */
|
||||
non_null()
|
||||
void do_dht(DHT *dht);
|
||||
|
||||
/*
|
||||
* Use these two functions to bootstrap the client.
|
||||
*/
|
||||
/**
|
||||
* @brief Sends a "get nodes" request to the given node with ip, port and public_key
|
||||
* to setup connections
|
||||
*/
|
||||
non_null()
|
||||
bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Resolves address into an IP address.
|
||||
*
|
||||
* If successful, sends a "get nodes" request to the given node with ip, port
|
||||
* and public_key to setup connections
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @retval 1 if the address could be converted into an IP address
|
||||
* @retval 0 otherwise
|
||||
*/
|
||||
non_null()
|
||||
int dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled,
|
||||
uint16_t port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Start sending packets after DHT loaded_friends_list and loaded_clients_list are set.
|
||||
*
|
||||
* @retval 0 if successful
|
||||
* @retval -1 otherwise
|
||||
*/
|
||||
non_null()
|
||||
int dht_connect_after_load(DHT *dht);
|
||||
|
||||
/* ROUTING FUNCTIONS */
|
||||
|
||||
/** @brief Send the given packet to node with public_key.
|
||||
*
|
||||
* @return number of bytes sent.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length);
|
||||
|
||||
/**
|
||||
* Send the following packet to everyone who tells us they are connected to friend_id.
|
||||
*
|
||||
* @return ip for friend.
|
||||
* @return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
|
||||
*/
|
||||
non_null()
|
||||
uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet *packet);
|
||||
|
||||
/** Function to handle crypto packets. */
|
||||
non_null(1) nullable(3, 4)
|
||||
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_cb *cb, void *object);
|
||||
|
||||
/* SAVE/LOAD functions */
|
||||
|
||||
/** Get the size of the DHT (for saving). */
|
||||
non_null()
|
||||
uint32_t dht_size(const DHT *dht);
|
||||
|
||||
/** Save the DHT in data where data is an array of size `dht_size()`. */
|
||||
non_null()
|
||||
void dht_save(const DHT *dht, uint8_t *data);
|
||||
|
||||
/** @brief Load the DHT from data of size size.
|
||||
*
|
||||
* @retval -1 if failure.
|
||||
* @retval 0 if success.
|
||||
*/
|
||||
non_null()
|
||||
int dht_load(DHT *dht, const uint8_t *data, uint32_t length);
|
||||
|
||||
/** Initialize DHT. */
|
||||
non_null()
|
||||
DHT *new_dht(const Logger *log, const Random *rng, const Network *ns, Mono_Time *mono_time, Networking_Core *net,
|
||||
bool hole_punching_enabled, bool lan_discovery_enabled);
|
||||
|
||||
nullable(1)
|
||||
void kill_dht(DHT *dht);
|
||||
|
||||
/**
|
||||
* @retval false if we are not connected to the DHT.
|
||||
* @retval true if we are.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_isconnected(const DHT *dht);
|
||||
|
||||
/**
|
||||
* @retval false if we are not connected or only connected to lan peers with the DHT.
|
||||
* @retval true if we are.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_non_lan_connected(const DHT *dht);
|
||||
|
||||
/** @brief Attempt to add client with ip_port and public_key to the friends client list
|
||||
* and close_clientlist.
|
||||
*
|
||||
* @return 1+ if the item is used in any list, 0 else
|
||||
*/
|
||||
non_null()
|
||||
uint32_t addto_lists(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Copies our own ip_port structure to `dest`.
|
||||
*
|
||||
* WAN addresses take priority over LAN addresses.
|
||||
*
|
||||
* This function will zero the `dest` buffer before use.
|
||||
*
|
||||
* @retval 0 if our ip port can't be found (this usually means we're not connected to the DHT).
|
||||
* @retval 1 if IP is a WAN address.
|
||||
* @retval 2 if IP is a LAN address.
|
||||
*/
|
||||
non_null()
|
||||
unsigned int ipport_self_copy(const DHT *dht, IP_Port *dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
49
external/toxcore/c-toxcore/toxcore/DHT_fuzz_test.cc
vendored
Normal file
49
external/toxcore/c-toxcore/toxcore/DHT_fuzz_test.cc
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#include "DHT.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "../testing/fuzzing/fuzz_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TestHandleRequest(Fuzz_Data &input)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void TestUnpackNodes(Fuzz_Data &input)
|
||||
{
|
||||
CONSUME1_OR_RETURN(const bool tcp_enabled, input);
|
||||
|
||||
const uint16_t node_count = 5;
|
||||
Node_format nodes[node_count];
|
||||
uint16_t processed_data_len;
|
||||
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();
|
||||
std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
|
||||
const int packed_size
|
||||
= pack_nodes(logger, packed.data(), packed.size(), nodes, packed_count);
|
||||
LOGGER_ASSERT(logger, packed_size == processed_data_len,
|
||||
"packed size (%d) != unpacked size (%d)", packed_size, processed_data_len);
|
||||
logger_kill(logger);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
fuzz_select_target(data, size, TestHandleRequest, TestUnpackNodes);
|
||||
return 0;
|
||||
}
|
231
external/toxcore/c-toxcore/toxcore/DHT_test.cc
vendored
Normal file
231
external/toxcore/c-toxcore/toxcore/DHT_test.cc
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
#include "DHT.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "crypto_core.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using PublicKey = std::array<uint8_t, CRYPTO_PUBLIC_KEY_SIZE>;
|
||||
using SecretKey = std::array<uint8_t, CRYPTO_SECRET_KEY_SIZE>;
|
||||
|
||||
struct KeyPair {
|
||||
PublicKey pk;
|
||||
SecretKey sk;
|
||||
|
||||
explicit KeyPair(const Random *rng) { crypto_new_keypair(rng, pk.data(), sk.data()); }
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
std::array<T, N> to_array(T const (&arr)[N])
|
||||
{
|
||||
std::array<T, N> stdarr;
|
||||
std::copy(arr, arr + N, stdarr.begin());
|
||||
return stdarr;
|
||||
}
|
||||
|
||||
PublicKey random_pk(const Random *rng)
|
||||
{
|
||||
PublicKey pk;
|
||||
random_bytes(rng, pk.data(), pk.size());
|
||||
return pk;
|
||||
}
|
||||
|
||||
TEST(IdClosest, IdenticalKeysAreSameDistance)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
PublicKey pk2 = pk1;
|
||||
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
}
|
||||
|
||||
TEST(IdClosest, DistanceIsCommutative)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
PublicKey pk0 = random_pk(rng);
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
PublicKey pk2 = random_pk(rng);
|
||||
|
||||
ASSERT_NE(pk1, pk2); // RNG can't produce the same random key twice
|
||||
|
||||
// Two non-equal keys can't have the same distance from any given key.
|
||||
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 1) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 2);
|
||||
}
|
||||
|
||||
if (id_closest(pk0.data(), pk1.data(), pk2.data()) == 2) {
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk2.data(), pk1.data()), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IdClosest, SmallXorDistanceIsCloser)
|
||||
{
|
||||
PublicKey const pk0 = {{0xaa}};
|
||||
PublicKey const pk1 = {{0xa0}};
|
||||
PublicKey const pk2 = {{0x0a}};
|
||||
|
||||
EXPECT_EQ(id_closest(pk0.data(), pk1.data(), pk2.data()), 1);
|
||||
}
|
||||
|
||||
TEST(IdClosest, DistinctKeysCannotHaveTheSameDistance)
|
||||
{
|
||||
PublicKey const pk0 = {{0x06}};
|
||||
PublicKey const pk1 = {{0x00}};
|
||||
PublicKey pk2 = {{0x00}};
|
||||
|
||||
for (uint8_t i = 1; i < 0xff; ++i) {
|
||||
pk2[0] = i;
|
||||
EXPECT_NE(id_closest(pk0.data(), pk1.data(), pk2.data()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddToList, OverridesKeysWithCloserKeys)
|
||||
{
|
||||
PublicKey const self_pk = {{0xaa}};
|
||||
PublicKey const keys[] = {
|
||||
{{0xa0}}, // closest
|
||||
{{0x0a}}, //
|
||||
{{0x0b}}, //
|
||||
{{0x0c}}, //
|
||||
{{0x0d}}, //
|
||||
{{0xa1}}, // closer than the 4 keys above
|
||||
};
|
||||
|
||||
std::array<Node_format, 4> nodes{};
|
||||
|
||||
IP_Port ip_port = {0};
|
||||
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[0].data(), &ip_port, self_pk.data()));
|
||||
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[1].data(), &ip_port, self_pk.data()));
|
||||
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[2].data(), &ip_port, self_pk.data()));
|
||||
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[3].data(), &ip_port, self_pk.data()));
|
||||
|
||||
EXPECT_EQ(to_array(nodes[0].public_key), keys[0]);
|
||||
EXPECT_EQ(to_array(nodes[1].public_key), keys[1]);
|
||||
EXPECT_EQ(to_array(nodes[2].public_key), keys[2]);
|
||||
EXPECT_EQ(to_array(nodes[3].public_key), keys[3]);
|
||||
|
||||
// key 4 is less close than keys 0-3
|
||||
EXPECT_FALSE(add_to_list(nodes.data(), nodes.size(), keys[4].data(), &ip_port, self_pk.data()));
|
||||
// 5 is closer than all except key 0
|
||||
EXPECT_TRUE(add_to_list(nodes.data(), nodes.size(), keys[5].data(), &ip_port, self_pk.data()));
|
||||
|
||||
EXPECT_EQ(to_array(nodes[0].public_key), keys[0]);
|
||||
EXPECT_EQ(to_array(nodes[1].public_key), keys[5]);
|
||||
EXPECT_EQ(to_array(nodes[2].public_key), keys[1]);
|
||||
EXPECT_EQ(to_array(nodes[3].public_key), keys[2]);
|
||||
}
|
||||
|
||||
TEST(Request, CreateAndParse)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
// Peers.
|
||||
const KeyPair sender(rng);
|
||||
const KeyPair receiver(rng);
|
||||
const uint8_t sent_pkt_id = CRYPTO_PACKET_FRIEND_REQ;
|
||||
|
||||
// Encoded packet.
|
||||
std::array<uint8_t, MAX_CRYPTO_REQUEST_SIZE> packet;
|
||||
|
||||
// Received components.
|
||||
PublicKey pk;
|
||||
std::array<uint8_t, MAX_CRYPTO_REQUEST_SIZE> incoming;
|
||||
uint8_t recvd_pkt_id;
|
||||
|
||||
// Request data: maximum payload is 918 bytes, so create a payload 1 byte larger than max.
|
||||
std::vector<uint8_t> outgoing(919);
|
||||
random_bytes(rng, outgoing.data(), outgoing.size());
|
||||
|
||||
EXPECT_LT(create_request(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(),
|
||||
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),
|
||||
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(),
|
||||
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);
|
||||
ASSERT_GE(recvd_length, 0);
|
||||
|
||||
EXPECT_EQ(
|
||||
std::vector<uint8_t>(incoming.begin(), incoming.begin() + recvd_length), outgoing);
|
||||
|
||||
outgoing.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnnounceNodes, SetAndTest)
|
||||
{
|
||||
Logger *log = logger_new();
|
||||
Mono_Time *mono_time = mono_time_new(nullptr, nullptr);
|
||||
const Random *rng = system_random();
|
||||
const Network *ns = system_network();
|
||||
Networking_Core *net = new_networking_no_udp(log, ns);
|
||||
DHT *dht = new_dht(log, rng, ns, mono_time, net, true, true);
|
||||
ASSERT_NE(dht, nullptr);
|
||||
|
||||
uint8_t pk_data[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
memcpy(pk_data, dht_get_self_public_key(dht), sizeof(pk_data));
|
||||
PublicKey self_pk = to_array(pk_data);
|
||||
|
||||
PublicKey pk1 = random_pk(rng);
|
||||
ASSERT_NE(pk1, self_pk);
|
||||
|
||||
// Test with maximally close key to self
|
||||
pk_data[CRYPTO_PUBLIC_KEY_SIZE - 1] = ~pk_data[CRYPTO_PUBLIC_KEY_SIZE - 1];
|
||||
PublicKey pk2 = to_array(pk_data);
|
||||
ASSERT_NE(pk2, pk1);
|
||||
|
||||
IP_Port ip_port = {0};
|
||||
ip_port.ip.family = net_family_ipv4();
|
||||
|
||||
set_announce_node(dht, pk1.data());
|
||||
set_announce_node(dht, pk2.data());
|
||||
|
||||
EXPECT_TRUE(addto_lists(dht, &ip_port, pk1.data()));
|
||||
EXPECT_TRUE(addto_lists(dht, &ip_port, pk2.data()));
|
||||
|
||||
Node_format nodes[MAX_SENT_NODES];
|
||||
EXPECT_EQ(0, get_close_nodes(dht, self_pk.data(), nodes, net_family_unspec(), true, true));
|
||||
set_announce_node(dht, pk1.data());
|
||||
set_announce_node(dht, pk2.data());
|
||||
EXPECT_EQ(2, get_close_nodes(dht, self_pk.data(), nodes, net_family_unspec(), true, true));
|
||||
|
||||
kill_dht(dht);
|
||||
kill_networking(net);
|
||||
mono_time_free(mono_time);
|
||||
logger_kill(log);
|
||||
}
|
||||
|
||||
} // namespace
|
387
external/toxcore/c-toxcore/toxcore/LAN_discovery.c
vendored
Normal file
387
external/toxcore/c-toxcore/toxcore/LAN_discovery.c
vendored
Normal file
@ -0,0 +1,387 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LAN discovery implementation.
|
||||
*/
|
||||
#include "LAN_discovery.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
// The mingw32/64 Windows library warns about including winsock2.h after
|
||||
// windows.h even though with the above it's a valid thing to do. So, to make
|
||||
// mingw32 headers happy, we include winsock2.h first.
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/netdevice.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#include "ccompat.h"
|
||||
#include "crypto_core.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_INTERFACES 16
|
||||
|
||||
|
||||
struct Broadcast_Info {
|
||||
uint32_t count;
|
||||
IP ips[MAX_INTERFACES];
|
||||
};
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
|
||||
if (broadcast == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
|
||||
unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
if (pAdapterInfo == nullptr) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAdapterInfo);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||
|
||||
if (pAdapterInfo == nullptr) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const int ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
|
||||
if (ret == NO_ERROR) {
|
||||
IP_ADAPTER_INFO *pAdapter = pAdapterInfo;
|
||||
|
||||
while (pAdapter != nullptr) {
|
||||
IP gateway = {0};
|
||||
IP subnet_mask = {0};
|
||||
|
||||
if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask)
|
||||
&& addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) {
|
||||
if (net_family_is_ipv4(gateway.family) && net_family_is_ipv4(subnet_mask.family)) {
|
||||
IP *ip = &broadcast->ips[broadcast->count];
|
||||
ip->family = net_family_ipv4();
|
||||
const uint32_t gateway_ip = net_ntohl(gateway.ip.v4.uint32);
|
||||
const uint32_t subnet_ip = net_ntohl(subnet_mask.ip.v4.uint32);
|
||||
const uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1;
|
||||
ip->ip.v4.uint32 = net_htonl(broadcast_ip);
|
||||
++broadcast->count;
|
||||
|
||||
if (broadcast->count >= MAX_INTERFACES) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
}
|
||||
|
||||
if (pAdapterInfo != nullptr) {
|
||||
free(pAdapterInfo);
|
||||
}
|
||||
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
#elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
|
||||
if (broadcast == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Not sure how many platforms this will run on,
|
||||
* so it's wrapped in `__linux__` for now.
|
||||
* Definitely won't work like this on Windows...
|
||||
*/
|
||||
const Socket sock = net_socket(ns, net_family_ipv4(), TOX_SOCK_STREAM, 0);
|
||||
|
||||
if (!sock_valid(sock)) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Configure ifconf for the ioctl call. */
|
||||
struct ifreq i_faces[MAX_INTERFACES];
|
||||
memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES);
|
||||
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_buf = (char *)i_faces;
|
||||
ifc.ifc_len = sizeof(i_faces);
|
||||
|
||||
if (ioctl(sock.sock, SIOCGIFCONF, &ifc) < 0) {
|
||||
kill_sock(ns, sock);
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* `ifc.ifc_len` is set by the `ioctl()` to the actual length used.
|
||||
* On usage of the complete array the call should be repeated with
|
||||
* a larger array, not done (640kB and 16 interfaces shall be
|
||||
* enough, for everybody!)
|
||||
*/
|
||||
const int n = ifc.ifc_len / sizeof(struct ifreq);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
/* there are interfaces with are incapable of broadcast */
|
||||
if (ioctl(sock.sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* moot check: only AF_INET returned (backwards compat.) */
|
||||
if (i_faces[i].ifr_broadaddr.sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const struct sockaddr_in *sock4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_broadaddr;
|
||||
|
||||
if (broadcast->count >= MAX_INTERFACES) {
|
||||
break;
|
||||
}
|
||||
|
||||
IP *ip = &broadcast->ips[broadcast->count];
|
||||
ip->family = net_family_ipv4();
|
||||
ip->ip.v4.uint32 = sock4->sin_addr.s_addr;
|
||||
|
||||
if (ip->ip.v4.uint32 == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++broadcast->count;
|
||||
}
|
||||
|
||||
kill_sock(ns, sock);
|
||||
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
#else // TODO(irungentoo): Other platforms?
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
return (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** @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.
|
||||
*/
|
||||
non_null()
|
||||
static bool send_broadcasts(const Networking_Core *net, const Broadcast_Info *broadcast, uint16_t port,
|
||||
const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (broadcast->count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < broadcast->count; ++i) {
|
||||
IP_Port ip_port;
|
||||
ip_port.ip = broadcast->ips[i];
|
||||
ip_port.port = port;
|
||||
sendpacket(net, &ip_port, data, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Return the broadcast ip. */
|
||||
static IP broadcast_ip(Family family_socket, Family family_broadcast)
|
||||
{
|
||||
IP ip;
|
||||
ip_reset(&ip);
|
||||
|
||||
if (net_family_is_ipv6(family_socket)) {
|
||||
if (net_family_is_ipv6(family_broadcast)) {
|
||||
ip.family = net_family_ipv6();
|
||||
/* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
/* `FE80::*:` MUST be exact, for that we would need to look over all
|
||||
* interfaces and check in which status they are */
|
||||
ip.ip.v6.uint8[ 0] = 0xFF;
|
||||
ip.ip.v6.uint8[ 1] = 0x02;
|
||||
ip.ip.v6.uint8[15] = 0x01;
|
||||
} else if (net_family_is_ipv4(family_broadcast)) {
|
||||
ip.family = net_family_ipv6();
|
||||
ip.ip.v6 = ip6_broadcast;
|
||||
}
|
||||
} else if (net_family_is_ipv4(family_socket) && net_family_is_ipv4(family_broadcast)) {
|
||||
ip.family = net_family_ipv4();
|
||||
ip.ip.v4 = ip4_broadcast;
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool ip4_is_local(const IP4 *ip4)
|
||||
{
|
||||
/* Loopback. */
|
||||
return ip4->uint8[0] == 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is IP a local ip or not.
|
||||
*/
|
||||
bool ip_is_local(const IP *ip)
|
||||
{
|
||||
if (net_family_is_ipv4(ip->family)) {
|
||||
return ip4_is_local(&ip->ip.v4);
|
||||
}
|
||||
|
||||
/* embedded IPv4-in-IPv6 */
|
||||
if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
|
||||
IP4 ip4;
|
||||
ip4.uint32 = ip->ip.v6.uint32[3];
|
||||
return ip4_is_local(&ip4);
|
||||
}
|
||||
|
||||
/* localhost in IPv6 (::1) */
|
||||
return ip->ip.v6.uint64[0] == 0 && ip->ip.v6.uint32[2] == 0 && ip->ip.v6.uint32[3] == net_htonl(1);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool ip4_is_lan(const IP4 *ip4)
|
||||
{
|
||||
/* 10.0.0.0 to 10.255.255.255 range. */
|
||||
if (ip4->uint8[0] == 10) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 172.16.0.0 to 172.31.255.255 range. */
|
||||
if (ip4->uint8[0] == 172 && ip4->uint8[1] >= 16 && ip4->uint8[1] <= 31) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 192.168.0.0 to 192.168.255.255 range. */
|
||||
if (ip4->uint8[0] == 192 && ip4->uint8[1] == 168) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 169.254.1.0 to 169.254.254.255 range. */
|
||||
if (ip4->uint8[0] == 169 && ip4->uint8[1] == 254 && ip4->uint8[2] != 0
|
||||
&& ip4->uint8[2] != 255) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
|
||||
* (shared address space to stack another layer of NAT) */
|
||||
return (ip4->uint8[0] == 100) && ((ip4->uint8[1] & 0xC0) == 0x40);
|
||||
}
|
||||
|
||||
bool ip_is_lan(const IP *ip)
|
||||
{
|
||||
if (ip_is_local(ip)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (net_family_is_ipv4(ip->family)) {
|
||||
return ip4_is_lan(&ip->ip.v4);
|
||||
}
|
||||
|
||||
if (net_family_is_ipv6(ip->family)) {
|
||||
/* autogenerated for each interface: `FE80::*` (up to `FEBF::*`)
|
||||
* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
if (((ip->ip.v6.uint8[0] == 0xFF) && (ip->ip.v6.uint8[1] < 3) && (ip->ip.v6.uint8[15] == 1)) ||
|
||||
((ip->ip.v6.uint8[0] == 0xFE) && ((ip->ip.v6.uint8[1] & 0xC0) == 0x80))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* embedded IPv4-in-IPv6 */
|
||||
if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
|
||||
IP4 ip4;
|
||||
ip4.uint32 = ip->ip.v6.uint32[3];
|
||||
return ip4_is_lan(&ip4);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk,
|
||||
uint16_t port)
|
||||
{
|
||||
if (broadcast == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1];
|
||||
data[0] = NET_PACKET_LAN_DISCOVERY;
|
||||
pk_copy(data + 1, dht_pk);
|
||||
|
||||
send_broadcasts(net, broadcast, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
bool res = false;
|
||||
IP_Port ip_port;
|
||||
ip_port.port = port;
|
||||
|
||||
/* IPv6 multicast */
|
||||
if (net_family_is_ipv6(net_family(net))) {
|
||||
ip_port.ip = broadcast_ip(net_family_ipv6(), net_family_ipv6());
|
||||
|
||||
if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is IPv6 */
|
||||
ip_port.ip = broadcast_ip(net_family(net), net_family_ipv4());
|
||||
|
||||
if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Broadcast_Info *lan_discovery_init(const Network *ns)
|
||||
{
|
||||
return fetch_broadcast_info(ns);
|
||||
}
|
||||
|
||||
void lan_discovery_kill(Broadcast_Info *broadcast)
|
||||
{
|
||||
free(broadcast);
|
||||
}
|
56
external/toxcore/c-toxcore/toxcore/LAN_discovery.h
vendored
Normal file
56
external/toxcore/c-toxcore/toxcore/LAN_discovery.h
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LAN discovery implementation.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
||||
#define C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
||||
|
||||
#include "network.h"
|
||||
|
||||
/**
|
||||
* Interval in seconds between LAN discovery packet sending.
|
||||
*/
|
||||
#define LAN_DISCOVERY_INTERVAL 10
|
||||
|
||||
typedef struct Broadcast_Info Broadcast_Info;
|
||||
|
||||
/**
|
||||
* Send a LAN discovery pcaket to the broadcast address with port port.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
non_null()
|
||||
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
* Discovers broadcast devices and IP addresses.
|
||||
*/
|
||||
non_null()
|
||||
Broadcast_Info *lan_discovery_init(const Network *ns);
|
||||
|
||||
/**
|
||||
* Free all resources associated with the broadcast info.
|
||||
*/
|
||||
nullable(1)
|
||||
void lan_discovery_kill(Broadcast_Info *broadcast);
|
||||
|
||||
/**
|
||||
* Is IP a local ip or not.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_is_local(const IP *ip);
|
||||
|
||||
/**
|
||||
* Checks if a given IP isn't routable.
|
||||
*
|
||||
* @return true if ip is a LAN ip, false if it is not.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_is_lan(const IP *ip);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
165
external/toxcore/c-toxcore/toxcore/Makefile.inc
vendored
Normal file
165
external/toxcore/c-toxcore/toxcore/Makefile.inc
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
lib_LTLIBRARIES += libtoxcore.la
|
||||
|
||||
libtoxcore_la_include_HEADERS = \
|
||||
../toxcore/tox.h
|
||||
|
||||
libtoxcore_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
|
||||
../third_party/cmp/cmp.h \
|
||||
../toxcore/attributes.h \
|
||||
../toxcore/bin_pack.c \
|
||||
../toxcore/bin_pack.h \
|
||||
../toxcore/bin_unpack.c \
|
||||
../toxcore/bin_unpack.h \
|
||||
../toxcore/ccompat.c \
|
||||
../toxcore/ccompat.h \
|
||||
../toxcore/events/conference_connected.c \
|
||||
../toxcore/events/conference_invite.c \
|
||||
../toxcore/events/conference_message.c \
|
||||
../toxcore/events/conference_peer_list_changed.c \
|
||||
../toxcore/events/conference_peer_name.c \
|
||||
../toxcore/events/conference_title.c \
|
||||
../toxcore/events/file_chunk_request.c \
|
||||
../toxcore/events/file_recv.c \
|
||||
../toxcore/events/file_recv_chunk.c \
|
||||
../toxcore/events/file_recv_control.c \
|
||||
../toxcore/events/friend_connection_status.c \
|
||||
../toxcore/events/friend_lossless_packet.c \
|
||||
../toxcore/events/friend_lossy_packet.c \
|
||||
../toxcore/events/friend_message.c \
|
||||
../toxcore/events/friend_name.c \
|
||||
../toxcore/events/friend_read_receipt.c \
|
||||
../toxcore/events/friend_request.c \
|
||||
../toxcore/events/friend_status.c \
|
||||
../toxcore/events/friend_status_message.c \
|
||||
../toxcore/events/friend_typing.c \
|
||||
../toxcore/events/events_alloc.c \
|
||||
../toxcore/events/events_alloc.h \
|
||||
../toxcore/events/self_connection_status.c \
|
||||
../toxcore/events/group_custom_packet.c \
|
||||
../toxcore/events/group_custom_private_packet.c \
|
||||
../toxcore/events/group_invite.c \
|
||||
../toxcore/events/group_join_fail.c \
|
||||
../toxcore/events/group_message.c \
|
||||
../toxcore/events/group_moderation.c \
|
||||
../toxcore/events/group_password.c \
|
||||
../toxcore/events/group_peer_exit.c \
|
||||
../toxcore/events/group_peer_join.c \
|
||||
../toxcore/events/group_peer_limit.c \
|
||||
../toxcore/events/group_peer_name.c \
|
||||
../toxcore/events/group_peer_status.c \
|
||||
../toxcore/events/group_privacy_state.c \
|
||||
../toxcore/events/group_private_message.c \
|
||||
../toxcore/events/group_self_join.c \
|
||||
../toxcore/events/group_topic.c \
|
||||
../toxcore/events/group_topic_lock.c \
|
||||
../toxcore/events/group_voice_state.c \
|
||||
../toxcore/DHT.h \
|
||||
../toxcore/DHT.c \
|
||||
../toxcore/mono_time.h \
|
||||
../toxcore/mono_time.c \
|
||||
../toxcore/network.h \
|
||||
../toxcore/network.c \
|
||||
../toxcore/crypto_core.h \
|
||||
../toxcore/crypto_core.c \
|
||||
../toxcore/timed_auth.h \
|
||||
../toxcore/timed_auth.c \
|
||||
../toxcore/ping_array.h \
|
||||
../toxcore/ping_array.c \
|
||||
../toxcore/net_crypto.h \
|
||||
../toxcore/net_crypto.c \
|
||||
../toxcore/friend_requests.h \
|
||||
../toxcore/friend_requests.c \
|
||||
../toxcore/LAN_discovery.h \
|
||||
../toxcore/LAN_discovery.c \
|
||||
../toxcore/friend_connection.h \
|
||||
../toxcore/friend_connection.c \
|
||||
../toxcore/Messenger.h \
|
||||
../toxcore/Messenger.c \
|
||||
../toxcore/ping.h \
|
||||
../toxcore/ping.c \
|
||||
../toxcore/shared_key_cache.h \
|
||||
../toxcore/shared_key_cache.c \
|
||||
../toxcore/state.h \
|
||||
../toxcore/state.c \
|
||||
../toxcore/tox.h \
|
||||
../toxcore/tox.c \
|
||||
../toxcore/tox_dispatch.h \
|
||||
../toxcore/tox_dispatch.c \
|
||||
../toxcore/tox_events.h \
|
||||
../toxcore/tox_events.c \
|
||||
../toxcore/tox_unpack.h \
|
||||
../toxcore/tox_unpack.c \
|
||||
../toxcore/tox_private.c \
|
||||
../toxcore/tox_private.h \
|
||||
../toxcore/tox_struct.h \
|
||||
../toxcore/tox_api.c \
|
||||
../toxcore/util.h \
|
||||
../toxcore/util.c \
|
||||
../toxcore/group.h \
|
||||
../toxcore/group.c \
|
||||
../toxcore/group_announce.h \
|
||||
../toxcore/group_announce.c \
|
||||
../toxcore/group_onion_announce.c \
|
||||
../toxcore/group_onion_announce.h \
|
||||
../toxcore/group_chats.h \
|
||||
../toxcore/group_chats.c \
|
||||
../toxcore/group_common.h \
|
||||
../toxcore/group_connection.c \
|
||||
../toxcore/group_connection.h \
|
||||
../toxcore/group_pack.c \
|
||||
../toxcore/group_pack.h \
|
||||
../toxcore/group_moderation.c \
|
||||
../toxcore/group_moderation.h \
|
||||
../toxcore/onion.h \
|
||||
../toxcore/onion.c \
|
||||
../toxcore/logger.h \
|
||||
../toxcore/logger.c \
|
||||
../toxcore/onion_announce.h \
|
||||
../toxcore/onion_announce.c \
|
||||
../toxcore/onion_client.h \
|
||||
../toxcore/onion_client.c \
|
||||
../toxcore/announce.h \
|
||||
../toxcore/announce.c \
|
||||
../toxcore/forwarding.h \
|
||||
../toxcore/forwarding.c \
|
||||
../toxcore/TCP_client.h \
|
||||
../toxcore/TCP_client.c \
|
||||
../toxcore/TCP_common.h \
|
||||
../toxcore/TCP_common.c \
|
||||
../toxcore/TCP_server.h \
|
||||
../toxcore/TCP_server.c \
|
||||
../toxcore/TCP_connection.h \
|
||||
../toxcore/TCP_connection.c \
|
||||
../toxcore/list.c \
|
||||
../toxcore/list.h
|
||||
|
||||
libtoxcore_la_CFLAGS = -I$(top_srcdir) \
|
||||
-I$(top_srcdir)/toxcore \
|
||||
$(LIBSODIUM_CFLAGS) \
|
||||
$(NACL_CFLAGS) \
|
||||
$(MSGPACK_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS) \
|
||||
-DCMP_NO_FLOAT=1
|
||||
|
||||
libtoxcore_la_LDFLAGS = $(LT_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS) \
|
||||
$(LIBSODIUM_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(MSGPACK_LDFLAGS) \
|
||||
$(MATH_LDFLAGS) \
|
||||
$(RT_LIBS) \
|
||||
$(WINSOCK2_LIBS)
|
||||
|
||||
libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \
|
||||
$(NACL_OBJECTS) \
|
||||
$(NACL_LIBS) \
|
||||
$(MSGPACK_LIBS) \
|
||||
$(PTHREAD_LIBS)
|
||||
|
||||
if SET_SO_VERSION
|
||||
|
||||
EXTRA_libtoxcore_la_DEPENDENCIES = ../so.version
|
||||
|
||||
endif
|
3777
external/toxcore/c-toxcore/toxcore/Messenger.c
vendored
Normal file
3777
external/toxcore/c-toxcore/toxcore/Messenger.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
891
external/toxcore/c-toxcore/toxcore/Messenger.h
vendored
Normal file
891
external/toxcore/c-toxcore/toxcore/Messenger.h
vendored
Normal file
@ -0,0 +1,891 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of a simple text chat only messenger on the tox network
|
||||
* core.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_MESSENGER_H
|
||||
#define C_TOXCORE_TOXCORE_MESSENGER_H
|
||||
|
||||
#include "TCP_server.h"
|
||||
#include "announce.h"
|
||||
#include "forwarding.h"
|
||||
#include "friend_connection.h"
|
||||
#include "friend_requests.h"
|
||||
#include "group_announce.h"
|
||||
#include "group_common.h"
|
||||
#include "logger.h"
|
||||
#include "net_crypto.h"
|
||||
#include "state.h"
|
||||
|
||||
#define MAX_NAME_LENGTH 128
|
||||
/* TODO(irungentoo): this must depend on other variable. */
|
||||
#define MAX_STATUSMESSAGE_LENGTH 1007
|
||||
/* Used for TCP relays in Messenger struct (may need to be `% 2 == 0`)*/
|
||||
#define NUM_SAVED_TCP_RELAYS 8
|
||||
/* This cannot be bigger than 256 */
|
||||
#define MAX_CONCURRENT_FILE_PIPES 256
|
||||
|
||||
|
||||
#define FRIEND_ADDRESS_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
|
||||
|
||||
typedef enum Message_Type {
|
||||
MESSAGE_NORMAL,
|
||||
MESSAGE_ACTION,
|
||||
} Message_Type;
|
||||
|
||||
// TODO(Jfreegman, Iphy): Remove this before merge
|
||||
#ifndef MESSENGER_DEFINED
|
||||
#define MESSENGER_DEFINED
|
||||
typedef struct Messenger Messenger;
|
||||
#endif // MESSENGER_DEFINED
|
||||
|
||||
// Returns the size of the data
|
||||
typedef uint32_t m_state_size_cb(const Messenger *m);
|
||||
|
||||
// Returns the new pointer to data
|
||||
typedef uint8_t *m_state_save_cb(const Messenger *m, uint8_t *data);
|
||||
|
||||
// Returns if there were any erros during loading
|
||||
typedef State_Load_Status m_state_load_cb(Messenger *m, const uint8_t *data, uint32_t length);
|
||||
|
||||
typedef struct Messenger_State_Plugin {
|
||||
State_Type type;
|
||||
m_state_size_cb *size;
|
||||
m_state_save_cb *save;
|
||||
m_state_load_cb *load;
|
||||
} Messenger_State_Plugin;
|
||||
|
||||
typedef struct Messenger_Options {
|
||||
bool ipv6enabled;
|
||||
bool udp_disabled;
|
||||
TCP_Proxy_Info proxy_info;
|
||||
uint16_t port_range[2];
|
||||
uint16_t tcp_server_port;
|
||||
|
||||
bool hole_punching_enabled;
|
||||
bool local_discovery_enabled;
|
||||
bool dht_announcements_enabled;
|
||||
|
||||
logger_cb *log_callback;
|
||||
void *log_context;
|
||||
void *log_user_data;
|
||||
|
||||
Messenger_State_Plugin *state_plugins;
|
||||
uint8_t state_plugins_length;
|
||||
} Messenger_Options;
|
||||
|
||||
|
||||
struct Receipts {
|
||||
uint32_t packet_num;
|
||||
uint32_t msg_id;
|
||||
struct Receipts *next;
|
||||
};
|
||||
|
||||
/** Status definitions. */
|
||||
typedef enum Friend_Status {
|
||||
NOFRIEND,
|
||||
FRIEND_ADDED,
|
||||
FRIEND_REQUESTED,
|
||||
FRIEND_CONFIRMED,
|
||||
FRIEND_ONLINE,
|
||||
} Friend_Status;
|
||||
|
||||
/** @brief Errors for m_addfriend
|
||||
*
|
||||
* FAERR - Friend Add Error
|
||||
*/
|
||||
typedef enum Friend_Add_Error {
|
||||
FAERR_TOOLONG = -1,
|
||||
FAERR_NOMESSAGE = -2,
|
||||
FAERR_OWNKEY = -3,
|
||||
FAERR_ALREADYSENT = -4,
|
||||
FAERR_BADCHECKSUM = -6,
|
||||
FAERR_SETNEWNOSPAM = -7,
|
||||
FAERR_NOMEM = -8,
|
||||
} Friend_Add_Error;
|
||||
|
||||
|
||||
/** Default start timeout in seconds between friend requests. */
|
||||
#define FRIENDREQUEST_TIMEOUT 5
|
||||
|
||||
typedef enum Connection_Status {
|
||||
CONNECTION_NONE,
|
||||
CONNECTION_TCP,
|
||||
CONNECTION_UDP,
|
||||
} Connection_Status;
|
||||
|
||||
/**
|
||||
* Represents userstatuses someone can have.
|
||||
*/
|
||||
typedef enum Userstatus {
|
||||
USERSTATUS_NONE,
|
||||
USERSTATUS_AWAY,
|
||||
USERSTATUS_BUSY,
|
||||
USERSTATUS_INVALID,
|
||||
} Userstatus;
|
||||
|
||||
#define FILE_ID_LENGTH 32
|
||||
|
||||
struct File_Transfers {
|
||||
uint64_t size;
|
||||
uint64_t transferred;
|
||||
uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */
|
||||
uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */
|
||||
uint32_t last_packet_number; /* number of the last packet sent. */
|
||||
uint64_t requested; /* total data requested by the request chunk callback */
|
||||
uint8_t id[FILE_ID_LENGTH];
|
||||
};
|
||||
typedef enum Filestatus {
|
||||
FILESTATUS_NONE,
|
||||
FILESTATUS_NOT_ACCEPTED,
|
||||
FILESTATUS_TRANSFERRING,
|
||||
// FILESTATUS_BROKEN,
|
||||
FILESTATUS_FINISHED,
|
||||
} Filestatus;
|
||||
|
||||
typedef enum File_Pause {
|
||||
FILE_PAUSE_NOT,
|
||||
FILE_PAUSE_US,
|
||||
FILE_PAUSE_OTHER,
|
||||
FILE_PAUSE_BOTH,
|
||||
} File_Pause;
|
||||
|
||||
typedef enum Filecontrol {
|
||||
FILECONTROL_ACCEPT,
|
||||
FILECONTROL_PAUSE,
|
||||
FILECONTROL_KILL,
|
||||
FILECONTROL_SEEK,
|
||||
} Filecontrol;
|
||||
|
||||
typedef enum Filekind {
|
||||
FILEKIND_DATA,
|
||||
FILEKIND_AVATAR,
|
||||
} Filekind;
|
||||
|
||||
|
||||
typedef void m_self_connection_status_cb(Messenger *m, Onion_Connection_Status connection_status, void *user_data);
|
||||
typedef void m_friend_status_cb(Messenger *m, uint32_t friend_number, unsigned int status, void *user_data);
|
||||
typedef void m_friend_connection_status_cb(Messenger *m, uint32_t friend_number, unsigned int connection_status,
|
||||
void *user_data);
|
||||
typedef void m_friend_message_cb(Messenger *m, uint32_t friend_number, unsigned int message_type,
|
||||
const uint8_t *message, size_t length, void *user_data);
|
||||
typedef void m_file_recv_control_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, unsigned int control,
|
||||
void *user_data);
|
||||
typedef void m_friend_request_cb(Messenger *m, const uint8_t *public_key, const uint8_t *message, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_name_cb(Messenger *m, uint32_t friend_number, const uint8_t *name, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_status_message_cb(Messenger *m, uint32_t friend_number, const uint8_t *message, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_typing_cb(Messenger *m, uint32_t friend_number, bool is_typing, void *user_data);
|
||||
typedef void m_friend_read_receipt_cb(Messenger *m, uint32_t friend_number, uint32_t message_id, void *user_data);
|
||||
typedef void m_file_recv_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint32_t kind,
|
||||
uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data);
|
||||
typedef void m_file_chunk_request_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
size_t length, void *user_data);
|
||||
typedef void m_file_recv_chunk_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *user_data);
|
||||
typedef void m_friend_lossy_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_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,
|
||||
uint8_t connection_status, 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 friendnumber, const uint8_t *data, size_t length,
|
||||
const uint8_t *group_name, size_t group_name_length, void *userdata);
|
||||
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 friendnumber, const uint8_t *data, uint16_t len, 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];
|
||||
int friendcon_id;
|
||||
|
||||
uint64_t friendrequest_lastsent; // Time at which the last friend request was sent.
|
||||
uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts.
|
||||
uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online.
|
||||
uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do.
|
||||
uint8_t name[MAX_NAME_LENGTH];
|
||||
uint16_t name_length;
|
||||
bool name_sent; // false if we didn't send our name to this friend, true if we have.
|
||||
uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmessage_length;
|
||||
bool statusmessage_sent;
|
||||
Userstatus userstatus;
|
||||
bool userstatus_sent;
|
||||
bool user_istyping;
|
||||
bool user_istyping_sent;
|
||||
bool is_typing;
|
||||
uint16_t info_size; // Length of the info.
|
||||
uint32_t message_id; // a semi-unique id used in read receipts.
|
||||
uint32_t friendrequest_nospam; // The nospam number used in the friend request.
|
||||
uint64_t last_seen_time;
|
||||
Connection_Status last_connection_udp_tcp;
|
||||
struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
|
||||
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;
|
||||
|
||||
struct Messenger {
|
||||
Logger *log;
|
||||
Mono_Time *mono_time;
|
||||
const Random *rng;
|
||||
const Network *ns;
|
||||
|
||||
Networking_Core *net;
|
||||
Net_Crypto *net_crypto;
|
||||
DHT *dht;
|
||||
|
||||
Forwarding *forwarding;
|
||||
Announcements *announce;
|
||||
|
||||
Onion *onion;
|
||||
Onion_Announce *onion_a;
|
||||
Onion_Client *onion_c;
|
||||
|
||||
Friend_Connections *fr_c;
|
||||
|
||||
TCP_Server *tcp_server;
|
||||
Friend_Requests *fr;
|
||||
uint8_t name[MAX_NAME_LENGTH];
|
||||
uint16_t name_length;
|
||||
|
||||
uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmessage_length;
|
||||
|
||||
Userstatus userstatus;
|
||||
|
||||
Friend *friendlist;
|
||||
uint32_t numfriends;
|
||||
|
||||
uint64_t lastdump;
|
||||
uint8_t is_receiving_file;
|
||||
|
||||
GC_Session *group_handler;
|
||||
GC_Announces_List *group_announce;
|
||||
|
||||
bool has_added_relays; // If the first connection has occurred in do_messenger
|
||||
|
||||
uint16_t num_loaded_relays;
|
||||
Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config
|
||||
|
||||
m_friend_request_cb *friend_request;
|
||||
m_friend_message_cb *friend_message;
|
||||
m_friend_name_cb *friend_namechange;
|
||||
m_friend_status_message_cb *friend_statusmessagechange;
|
||||
m_friend_status_cb *friend_userstatuschange;
|
||||
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; /* Set by new_groupchats()*/
|
||||
m_conference_invite_cb *conference_invite;
|
||||
|
||||
m_group_invite_cb *group_invite;
|
||||
|
||||
m_file_recv_cb *file_sendrequest;
|
||||
m_file_recv_control_cb *file_filecontrol;
|
||||
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;
|
||||
|
||||
m_self_connection_status_cb *core_connection_change;
|
||||
Onion_Connection_Status last_connection_status;
|
||||
|
||||
Messenger_Options options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the friendnumber passed is valid in the Messenger object.
|
||||
*
|
||||
* @param friendnumber The index in the friend list.
|
||||
*/
|
||||
non_null()
|
||||
bool friend_is_valid(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/**
|
||||
* Format: `[real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]`
|
||||
*
|
||||
* @param[out] address FRIEND_ADDRESS_SIZE byte address to give to others.
|
||||
*/
|
||||
non_null()
|
||||
void getaddress(const Messenger *m, uint8_t *address);
|
||||
|
||||
/**
|
||||
* Add a friend.
|
||||
*
|
||||
* Set the data that will be sent along with friend request.
|
||||
*
|
||||
* @param address is the address of the friend (returned by getaddress of the friend
|
||||
* you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.
|
||||
* TODO(irungentoo): add checksum.
|
||||
* @param data is the data.
|
||||
* @param length is the length.
|
||||
*
|
||||
* @return the friend number if success.
|
||||
* @retval FA_TOOLONG if message length is too long.
|
||||
* @retval FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
|
||||
* @retval FAERR_OWNKEY if user's own key.
|
||||
* @retval FAERR_ALREADYSENT if friend request already sent or already a friend.
|
||||
* @retval FAERR_BADCHECKSUM if bad checksum in address.
|
||||
* @retval FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
|
||||
* (the nospam for that friend was set to the new one).
|
||||
* @retval FAERR_NOMEM if increasing the friend list size fails.
|
||||
*/
|
||||
non_null()
|
||||
int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length);
|
||||
|
||||
|
||||
/** @brief Add a friend without sending a friendrequest.
|
||||
* @return the friend number if success.
|
||||
* @retval -3 if user's own key.
|
||||
* @retval -4 if friend request already sent or already a friend.
|
||||
* @retval -6 if bad checksum in address.
|
||||
* @retval -8 if increasing the friend list size fails.
|
||||
*/
|
||||
non_null()
|
||||
int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk);
|
||||
|
||||
/** @brief Initializes the friend connection and onion connection for a groupchat.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool m_create_group_connection(Messenger *m, GC_Chat *chat);
|
||||
|
||||
/*
|
||||
* Kills the friend connection for a groupchat.
|
||||
*/
|
||||
non_null()
|
||||
void m_kill_group_connection(Messenger *m, const GC_Chat *chat);
|
||||
|
||||
/** @return the friend number associated to that public key.
|
||||
* @retval -1 if no such friend.
|
||||
*/
|
||||
non_null()
|
||||
int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk);
|
||||
|
||||
/** @brief Copies the public key associated to that friend id into real_pk buffer.
|
||||
*
|
||||
* Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk);
|
||||
|
||||
/** @return friend connection id on success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int getfriendcon_id(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Remove a friend.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_delfriend(Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Checks friend's connection status.
|
||||
*
|
||||
* @retval CONNECTION_UDP (2) if friend is directly connected to us (Online UDP).
|
||||
* @retval CONNECTION_TCP (1) if friend is connected to us (Online TCP).
|
||||
* @retval CONNECTION_NONE (0) if friend is not connected to us (Offline).
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/**
|
||||
* Checks if there exists a friend with given friendnumber.
|
||||
*
|
||||
* @param friendnumber The index in the friend list.
|
||||
*
|
||||
* @retval true if friend exists.
|
||||
* @retval false if friend doesn't exist.
|
||||
*/
|
||||
non_null()
|
||||
bool m_friend_exists(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Send a message of type to an online friend.
|
||||
*
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if too large.
|
||||
* @retval -3 if friend not online.
|
||||
* @retval -4 if send failed (because queue is full).
|
||||
* @retval -5 if bad type.
|
||||
* @retval 0 if success.
|
||||
*
|
||||
* The value in message_id will be passed to your read_receipt callback when the other receives the message.
|
||||
*/
|
||||
non_null(1, 4) nullable(6)
|
||||
int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,
|
||||
uint32_t *message_id);
|
||||
|
||||
|
||||
/** @brief Set the name and name_length of a friend.
|
||||
*
|
||||
* name must be a string of maximum MAX_NAME_LENGTH length.
|
||||
* length must be at least 1 byte.
|
||||
* length is the length of name with the NULL terminator.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length);
|
||||
|
||||
/** @brief Set our nickname.
|
||||
*
|
||||
* name must be a string of maximum MAX_NAME_LENGTH length.
|
||||
* length must be at least 1 byte.
|
||||
* length is the length of name with the NULL terminator.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int setname(Messenger *m, const uint8_t *name, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Get your nickname.
|
||||
*
|
||||
* m - The messenger context to use.
|
||||
* name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
|
||||
*
|
||||
* @return length of the name.
|
||||
* @retval 0 on error.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t getself_name(const Messenger *m, uint8_t *name);
|
||||
|
||||
/** @brief Get name of friendnumber and put it in name.
|
||||
*
|
||||
* name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
|
||||
*
|
||||
* @return length of name if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int getname(const Messenger *m, int32_t friendnumber, uint8_t *name);
|
||||
|
||||
/** @return the length of name, including null on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_get_name_size(const Messenger *m, int32_t friendnumber);
|
||||
non_null() int m_get_self_name_size(const Messenger *m);
|
||||
|
||||
/** @brief Set our user status.
|
||||
* You are responsible for freeing status after.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length);
|
||||
non_null() int m_set_userstatus(Messenger *m, uint8_t status);
|
||||
|
||||
/**
|
||||
* Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
|
||||
*
|
||||
* @return the length of friendnumber's status message, including null on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber);
|
||||
non_null() int m_get_self_statusmessage_size(const Messenger *m);
|
||||
|
||||
/** @brief Copy friendnumber's status message into buf, truncating if size is over maxlen.
|
||||
*
|
||||
* Get the size you need to allocate from m_get_statusmessage_size.
|
||||
* The self variant will copy our own status message.
|
||||
*
|
||||
* @return the length of the copied data on success
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen);
|
||||
non_null() int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf);
|
||||
|
||||
/** @brief return one of Userstatus values.
|
||||
*
|
||||
* Values unknown to your application should be represented as USERSTATUS_NONE.
|
||||
* As above, the self variant will return our own Userstatus.
|
||||
* If friendnumber is invalid, this shall return USERSTATUS_INVALID.
|
||||
*/
|
||||
non_null() uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);
|
||||
non_null() uint8_t m_get_self_userstatus(const Messenger *m);
|
||||
|
||||
|
||||
/** @brief returns timestamp of last time friendnumber was seen online or 0 if never seen.
|
||||
* if friendnumber is invalid this function will return UINT64_MAX.
|
||||
*/
|
||||
non_null() uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Set our typing status for a friend.
|
||||
* You are responsible for turning it on or off.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_set_usertyping(Messenger *m, int32_t friendnumber, bool is_typing);
|
||||
|
||||
/** @brief Get the typing status of a friend.
|
||||
*
|
||||
* @retval -1 if friend number is invalid.
|
||||
* @retval 0 if friend is not typing.
|
||||
* @retval 1 if friend is typing.
|
||||
*/
|
||||
non_null()
|
||||
int m_get_istyping(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** Set the function that will be executed when a friend request is received. */
|
||||
non_null(1) nullable(2)
|
||||
void m_callback_friendrequest(Messenger *m, m_friend_request_cb *function);
|
||||
|
||||
/** Set the function that will be executed when a message from a friend is received. */
|
||||
non_null() void m_callback_friendmessage(Messenger *m, m_friend_message_cb *function);
|
||||
|
||||
/** @brief Set the callback for name changes.
|
||||
* You are not responsible for freeing newname.
|
||||
*/
|
||||
non_null() void m_callback_namechange(Messenger *m, m_friend_name_cb *function);
|
||||
|
||||
/** @brief Set the callback for status message changes.
|
||||
*
|
||||
* You are not responsible for freeing newstatus
|
||||
*/
|
||||
non_null() void m_callback_statusmessage(Messenger *m, m_friend_status_message_cb *function);
|
||||
|
||||
/** @brief Set the callback for status type changes. */
|
||||
non_null() void m_callback_userstatus(Messenger *m, m_friend_status_cb *function);
|
||||
|
||||
/** @brief Set the callback for typing changes. */
|
||||
non_null() void m_callback_typingchange(Messenger *m, m_friend_typing_cb *function);
|
||||
|
||||
/** @brief Set the callback for read receipts.
|
||||
*
|
||||
* If you are keeping a record of returns from m_sendmessage,
|
||||
* receipt might be one of those values, meaning the message
|
||||
* has been received on the other side.
|
||||
* Since core doesn't track ids for you, receipt may not correspond to any message.
|
||||
* In that case, you should discard it.
|
||||
*/
|
||||
non_null() void m_callback_read_receipt(Messenger *m, m_friend_read_receipt_cb *function);
|
||||
|
||||
/** @brief Set the callback for connection status changes.
|
||||
*
|
||||
* Status:
|
||||
* - 0: friend went offline after being previously online.
|
||||
* - 1: friend went online.
|
||||
*
|
||||
* Note that this callback is not called when adding friends, thus the
|
||||
* "after being previously online" part.
|
||||
* It's assumed that when adding friends, their connection status is offline.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*** CONFERENCES */
|
||||
|
||||
/** @brief Set the callback for conference invites. */
|
||||
non_null(1) nullable(2)
|
||||
void m_callback_conference_invite(Messenger *m, m_conference_invite_cb *function);
|
||||
|
||||
/* Set the callback for group invites.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
void m_callback_group_invite(Messenger *m, m_group_invite_cb *function);
|
||||
|
||||
|
||||
/** @brief Send a conference invite packet.
|
||||
*
|
||||
* return true on success
|
||||
* return false on failure
|
||||
*/
|
||||
non_null()
|
||||
bool send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
/* Send a group invite packet.
|
||||
*
|
||||
* WARNING: Return-value semantics are different than for
|
||||
* send_conference_invite_packet().
|
||||
*
|
||||
* return true on success
|
||||
*/
|
||||
non_null()
|
||||
bool send_group_invite_packet(const Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
|
||||
/*** FILE SENDING */
|
||||
|
||||
|
||||
/** @brief Set the callback for file send requests. */
|
||||
non_null() void callback_file_sendrequest(Messenger *m, m_file_recv_cb *function);
|
||||
|
||||
|
||||
/** @brief Set the callback for file control requests. */
|
||||
non_null() void callback_file_control(Messenger *m, m_file_recv_control_cb *function);
|
||||
|
||||
/** @brief Set the callback for file data. */
|
||||
non_null() void callback_file_data(Messenger *m, m_file_recv_chunk_cb *function);
|
||||
|
||||
/** @brief Set the callback for file request chunk. */
|
||||
non_null() void callback_file_reqchunk(Messenger *m, m_file_chunk_request_cb *function);
|
||||
|
||||
|
||||
/** @brief Copy the file transfer file id to file_id
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if filenumber not valid
|
||||
*/
|
||||
non_null()
|
||||
int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id);
|
||||
|
||||
/** @brief Send a file send request.
|
||||
*
|
||||
* Maximum filename length is 255 bytes.
|
||||
*
|
||||
* @return file number on success
|
||||
* @retval -1 if friend not found.
|
||||
* @retval -2 if filename length invalid.
|
||||
* @retval -3 if no more file sending slots left.
|
||||
* @retval -4 if could not send packet (friend offline).
|
||||
*/
|
||||
non_null()
|
||||
long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
|
||||
const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length);
|
||||
|
||||
/** @brief Send a file control request.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if file number invalid.
|
||||
* @retval -4 if file control is bad.
|
||||
* @retval -5 if file already paused.
|
||||
* @retval -6 if resume file failed because it was only paused by the other.
|
||||
* @retval -7 if resume file failed because it wasn't paused.
|
||||
* @retval -8 if packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control);
|
||||
|
||||
/** @brief Send a seek file control request.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if file number invalid.
|
||||
* @retval -4 if not receiving file.
|
||||
* @retval -5 if file status wrong.
|
||||
* @retval -6 if position bad.
|
||||
* @retval -8 if packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position);
|
||||
|
||||
/** @brief Send file data.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if filenumber invalid.
|
||||
* @retval -4 if file transfer not transferring.
|
||||
* @retval -5 if bad data size.
|
||||
* @retval -6 if packet queue full.
|
||||
* @retval -7 if wrong position.
|
||||
*/
|
||||
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.
|
||||
* @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.
|
||||
*/
|
||||
non_null()
|
||||
int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);
|
||||
|
||||
|
||||
/** @brief Set handlers for custom lossless packets. */
|
||||
non_null()
|
||||
void custom_lossless_packet_registerhandler(Messenger *m, m_friend_lossless_packet_cb *lossless_packethandler);
|
||||
|
||||
/** @brief High level function to send custom lossless 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.
|
||||
*/
|
||||
non_null()
|
||||
int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);
|
||||
|
||||
/*** Messenger constructor/destructor/operations. */
|
||||
|
||||
typedef enum Messenger_Error {
|
||||
MESSENGER_ERROR_NONE,
|
||||
MESSENGER_ERROR_PORT,
|
||||
MESSENGER_ERROR_TCP_SERVER,
|
||||
MESSENGER_ERROR_OTHER,
|
||||
} Messenger_Error;
|
||||
|
||||
/** @brief Run this at startup.
|
||||
*
|
||||
* @return allocated instance of Messenger on success.
|
||||
* @retval 0 if there are problems.
|
||||
*
|
||||
* if error is not NULL it will be set to one of the values in the enum above.
|
||||
*/
|
||||
non_null()
|
||||
Messenger *new_messenger(Mono_Time *mono_time, const Random *rng, const Network *ns, Messenger_Options *options, Messenger_Error *error);
|
||||
|
||||
/** @brief Run this before closing shop.
|
||||
*
|
||||
* Free all datastructures.
|
||||
*/
|
||||
nullable(1)
|
||||
void kill_messenger(Messenger *m);
|
||||
|
||||
/** @brief The main loop that needs to be run at least 20 times per second. */
|
||||
non_null(1) nullable(2)
|
||||
void do_messenger(Messenger *m, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Return the time in milliseconds before `do_messenger()` should be called again
|
||||
* for optimal performance.
|
||||
*
|
||||
* @return time (in ms) before the next `do_messenger()` needs to be run on success.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t messenger_run_interval(const Messenger *m);
|
||||
|
||||
/* SAVING AND LOADING FUNCTIONS: */
|
||||
|
||||
/** @brief Registers a state plugin for saving, loading, and getting the size of a section of the save.
|
||||
*
|
||||
* @retval true on success
|
||||
* @retval false on error
|
||||
*/
|
||||
non_null()
|
||||
bool m_register_state_plugin(Messenger *m, State_Type type,
|
||||
m_state_size_cb *size_callback,
|
||||
m_state_load_cb *load_callback,
|
||||
m_state_save_cb *save_callback);
|
||||
|
||||
/** return size of the messenger data (for saving). */
|
||||
non_null()
|
||||
uint32_t messenger_size(const Messenger *m);
|
||||
|
||||
/** Save the messenger in data (must be allocated memory of size at least `Messenger_size()`) */
|
||||
non_null()
|
||||
uint8_t *messenger_save(const Messenger *m, uint8_t *data);
|
||||
|
||||
/** @brief Load a state section.
|
||||
*
|
||||
* @param data Data to load.
|
||||
* @param length Length of data.
|
||||
* @param type Type of section (`STATE_TYPE_*`).
|
||||
* @param status Result of loading section is stored here if the section is handled.
|
||||
* @return true iff section handled.
|
||||
*/
|
||||
non_null()
|
||||
bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
|
||||
State_Load_Status *status);
|
||||
|
||||
/** @brief Return the number of friends in the instance m.
|
||||
*
|
||||
* You should use this to determine how much memory to allocate
|
||||
* for copy_friendlist.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t count_friendlist(const Messenger *m);
|
||||
|
||||
/** @brief Copy a list of valid friend IDs into the array out_list.
|
||||
* If out_list is NULL, returns 0.
|
||||
* Otherwise, returns the number of elements copied.
|
||||
* If the array was too small, the contents
|
||||
* of out_list will be truncated to list_size.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size);
|
||||
|
||||
non_null()
|
||||
bool m_is_receiving_file(Messenger *m);
|
||||
|
||||
#endif
|
1005
external/toxcore/c-toxcore/toxcore/TCP_client.c
vendored
Normal file
1005
external/toxcore/c-toxcore/toxcore/TCP_client.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
154
external/toxcore/c-toxcore/toxcore/TCP_client.h
vendored
Normal file
154
external/toxcore/c-toxcore/toxcore/TCP_client.h
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the TCP relay client part of Tox.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_CLIENT_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_CLIENT_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "forwarding.h"
|
||||
#include "mono_time.h"
|
||||
#include "network.h"
|
||||
|
||||
#define TCP_CONNECTION_TIMEOUT 10
|
||||
|
||||
typedef enum TCP_Proxy_Type {
|
||||
TCP_PROXY_NONE,
|
||||
TCP_PROXY_HTTP,
|
||||
TCP_PROXY_SOCKS5,
|
||||
} TCP_Proxy_Type;
|
||||
|
||||
typedef struct TCP_Proxy_Info {
|
||||
IP_Port ip_port;
|
||||
uint8_t proxy_type; // a value from TCP_PROXY_TYPE
|
||||
} TCP_Proxy_Info;
|
||||
|
||||
typedef enum TCP_Client_Status {
|
||||
TCP_CLIENT_NO_STATUS,
|
||||
TCP_CLIENT_PROXY_HTTP_CONNECTING,
|
||||
TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
|
||||
TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
|
||||
TCP_CLIENT_CONNECTING,
|
||||
TCP_CLIENT_UNCONFIRMED,
|
||||
TCP_CLIENT_CONFIRMED,
|
||||
TCP_CLIENT_DISCONNECTED,
|
||||
} TCP_Client_Status;
|
||||
|
||||
typedef struct TCP_Client_Connection TCP_Client_Connection;
|
||||
|
||||
non_null()
|
||||
const uint8_t *tcp_con_public_key(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
IP_Port tcp_con_ip_port(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con);
|
||||
|
||||
non_null()
|
||||
void *tcp_con_custom_object(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object);
|
||||
non_null()
|
||||
void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value);
|
||||
|
||||
/** Create new TCP connection to ip_port/public_key */
|
||||
non_null(1, 2, 3, 4, 5, 6, 7, 8) nullable(9)
|
||||
TCP_Client_Connection *new_TCP_connection(
|
||||
const Logger *logger, const Mono_Time *mono_time, const Random *rng, const Network *ns, const IP_Port *ip_port,
|
||||
const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key,
|
||||
const TCP_Proxy_Info *proxy_info);
|
||||
|
||||
/** Run the TCP connection */
|
||||
non_null(1, 2, 3) nullable(4)
|
||||
void do_TCP_connection(const Logger *logger, const Mono_Time *mono_time,
|
||||
TCP_Client_Connection *tcp_connection, void *userdata);
|
||||
|
||||
/** Kill the TCP connection */
|
||||
nullable(1)
|
||||
void kill_TCP_connection(TCP_Client_Connection *tcp_connection);
|
||||
|
||||
typedef int tcp_onion_response_cb(void *object, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_onion_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *data, uint16_t length);
|
||||
non_null()
|
||||
void onion_response_handler(TCP_Client_Connection *con, tcp_onion_response_cb *onion_callback, void *object);
|
||||
|
||||
non_null()
|
||||
int send_forward_request_tcp(const Logger *logger, TCP_Client_Connection *con, const IP_Port *dest, const uint8_t *data,
|
||||
uint16_t length);
|
||||
non_null()
|
||||
void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwarded_response_callback, void *object);
|
||||
|
||||
typedef int tcp_routing_response_cb(void *object, uint8_t connection_id, const uint8_t *public_key);
|
||||
typedef int tcp_routing_status_cb(void *object, uint32_t number, uint8_t connection_id, uint8_t status);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_routing_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key);
|
||||
non_null()
|
||||
void routing_response_handler(TCP_Client_Connection *con, tcp_routing_response_cb *response_callback, void *object);
|
||||
non_null()
|
||||
void routing_status_handler(TCP_Client_Connection *con, tcp_routing_status_cb *status_callback, void *object);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_disconnect_request(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id);
|
||||
|
||||
/** @brief Set the number that will be used as an argument in the callbacks related to con_id.
|
||||
*
|
||||
* When not set by this function, the number is -1.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number);
|
||||
|
||||
typedef int tcp_routing_data_cb(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data,
|
||||
uint16_t length, void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int send_data(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length);
|
||||
non_null()
|
||||
void routing_data_handler(TCP_Client_Connection *con, tcp_routing_data_cb *data_callback, void *object);
|
||||
|
||||
typedef int tcp_oob_data_cb(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int send_oob_packet(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data,
|
||||
uint16_t length);
|
||||
non_null()
|
||||
void oob_data_handler(TCP_Client_Connection *con, tcp_oob_data_cb *oob_data_callback, void *object);
|
||||
|
||||
|
||||
#endif
|
305
external/toxcore/c-toxcore/toxcore/TCP_common.c
vendored
Normal file
305
external/toxcore/c-toxcore/toxcore/TCP_common.c
vendored
Normal file
@ -0,0 +1,305 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
#include "TCP_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccompat.h"
|
||||
|
||||
void wipe_priority_list(TCP_Priority_List *p)
|
||||
{
|
||||
while (p != nullptr) {
|
||||
TCP_Priority_List *pp = p;
|
||||
p = p->next;
|
||||
free(pp->data);
|
||||
free(pp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con)
|
||||
{
|
||||
if (con->last_packet_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint16_t left = con->last_packet_length - con->last_packet_sent;
|
||||
const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port);
|
||||
|
||||
if (len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == left) {
|
||||
con->last_packet_length = 0;
|
||||
con->last_packet_sent = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
con->last_packet_sent += len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
int send_pending_data(const Logger *logger, TCP_Connection *con)
|
||||
{
|
||||
/* finish sending current non-priority packet */
|
||||
if (send_pending_data_nonpriority(logger, con) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TCP_Priority_List *p = con->priority_queue_start;
|
||||
|
||||
while (p != nullptr) {
|
||||
const uint16_t left = p->size - p->sent;
|
||||
const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port);
|
||||
|
||||
if (len != left) {
|
||||
if (len > 0) {
|
||||
p->sent += len;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TCP_Priority_List *pp = p;
|
||||
p = p->next;
|
||||
free(pp->data);
|
||||
free(pp);
|
||||
}
|
||||
|
||||
con->priority_queue_start = p;
|
||||
|
||||
if (p == nullptr) {
|
||||
con->priority_queue_end = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval false on failure (only if calloc fails)
|
||||
* @retval true on success
|
||||
*/
|
||||
non_null()
|
||||
static bool add_priority(TCP_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent)
|
||||
{
|
||||
TCP_Priority_List *p = con->priority_queue_end;
|
||||
TCP_Priority_List *new_list = (TCP_Priority_List *)calloc(1, sizeof(TCP_Priority_List));
|
||||
|
||||
if (new_list == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new_list->next = nullptr;
|
||||
new_list->size = size;
|
||||
new_list->sent = sent;
|
||||
new_list->data = (uint8_t *)malloc(size);
|
||||
|
||||
if (new_list->data == nullptr) {
|
||||
free(new_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(new_list->data, packet, size);
|
||||
|
||||
if (p != nullptr) {
|
||||
p->next = new_list;
|
||||
} else {
|
||||
con->priority_queue_start = new_list;
|
||||
}
|
||||
|
||||
con->priority_queue_end = new_list;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
int write_packet_TCP_secure_connection(const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
|
||||
bool priority)
|
||||
{
|
||||
if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool sendpriority = true;
|
||||
|
||||
if (send_pending_data(logger, con) == -1) {
|
||||
if (priority) {
|
||||
sendpriority = false;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE);
|
||||
|
||||
uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
|
||||
memcpy(packet, &c_length, sizeof(uint16_t));
|
||||
int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
|
||||
|
||||
if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
len = sendpriority ? net_send(con->ns, logger, con->sock, packet, SIZEOF_VLA(packet), &con->ip_port) : 0;
|
||||
|
||||
if (len <= 0) {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
increment_nonce(con->sent_nonce);
|
||||
|
||||
if ((unsigned int)len == SIZEOF_VLA(packet)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return add_priority(con, packet, SIZEOF_VLA(packet), len) ? 1 : 0;
|
||||
}
|
||||
|
||||
len = net_send(con->ns, logger, con->sock, packet, SIZEOF_VLA(packet), &con->ip_port);
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
increment_nonce(con->sent_nonce);
|
||||
|
||||
if ((unsigned int)len == SIZEOF_VLA(packet)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(con->last_packet, packet, SIZEOF_VLA(packet));
|
||||
con->last_packet_length = SIZEOF_VLA(packet);
|
||||
con->last_packet_sent = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @brief Read length bytes from socket.
|
||||
*
|
||||
* return length on success
|
||||
* return -1 on failure/no data in buffer.
|
||||
*/
|
||||
int read_TCP_packet(const Logger *logger, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port)
|
||||
{
|
||||
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
|
||||
|
||||
if (count < length) {
|
||||
LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int len = net_recv(ns, logger, sock, data, length, ip_port);
|
||||
|
||||
if (len != length) {
|
||||
LOGGER_ERROR(logger, "FAIL recv packet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** @brief Read the next two bytes in TCP stream then convert them to
|
||||
* length (host byte order).
|
||||
*
|
||||
* return length on success
|
||||
* return 0 if nothing has been read from socket.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
static uint16_t read_TCP_length(const Logger *logger, const Network *ns, Socket sock, const IP_Port *ip_port)
|
||||
{
|
||||
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
|
||||
|
||||
if (count >= sizeof(uint16_t)) {
|
||||
uint8_t length_buf[sizeof(uint16_t)];
|
||||
const int len = net_recv(ns, logger, sock, length_buf, sizeof(length_buf), ip_port);
|
||||
|
||||
if (len != sizeof(uint16_t)) {
|
||||
LOGGER_ERROR(logger, "FAIL recv packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t length;
|
||||
net_unpack_u16(length_buf, &length);
|
||||
|
||||
if (length > MAX_PACKET_SIZE) {
|
||||
LOGGER_ERROR(logger, "TCP packet too large: %d > %d", length, MAX_PACKET_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return length of received packet on success.
|
||||
* @retval 0 if could not read any packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
int read_packet_TCP_secure_connection(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint16_t *next_packet_length,
|
||||
const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
|
||||
uint16_t max_len, const IP_Port *ip_port)
|
||||
{
|
||||
if (*next_packet_length == 0) {
|
||||
const uint16_t len = read_TCP_length(logger, ns, sock, ip_port);
|
||||
|
||||
if (len == (uint16_t) -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*next_packet_length = len;
|
||||
}
|
||||
|
||||
if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) {
|
||||
LOGGER_DEBUG(logger, "packet too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, data_encrypted, (int) *next_packet_length);
|
||||
const int len_packet = read_TCP_packet(logger, ns, sock, data_encrypted, *next_packet_length, ip_port);
|
||||
|
||||
if (len_packet == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len_packet != *next_packet_length) {
|
||||
LOGGER_WARNING(logger, "invalid packet length: %d, expected %d", len_packet, *next_packet_length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*next_packet_length = 0;
|
||||
|
||||
const int len = decrypt_data_symmetric(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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
increment_nonce(recv_nonce);
|
||||
|
||||
return len;
|
||||
}
|
124
external/toxcore/c-toxcore/toxcore/TCP_common.h
vendored
Normal file
124
external/toxcore/c-toxcore/toxcore/TCP_common.h
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_COMMON_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_COMMON_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "network.h"
|
||||
|
||||
typedef struct TCP_Priority_List TCP_Priority_List;
|
||||
struct TCP_Priority_List {
|
||||
TCP_Priority_List *next;
|
||||
uint16_t size;
|
||||
uint16_t sent;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
nullable(1)
|
||||
void wipe_priority_list(TCP_Priority_List *p);
|
||||
|
||||
#define NUM_RESERVED_PORTS 16
|
||||
#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS)
|
||||
|
||||
#ifdef USE_TEST_NETWORK
|
||||
#define TCP_PACKET_FORWARD_REQUEST 11
|
||||
#define TCP_PACKET_FORWARDING 10
|
||||
#define TCP_PACKET_ROUTING_REQUEST 9
|
||||
#define TCP_PACKET_ROUTING_RESPONSE 8
|
||||
#define TCP_PACKET_CONNECTION_NOTIFICATION 7
|
||||
#define TCP_PACKET_DISCONNECT_NOTIFICATION 6
|
||||
#define TCP_PACKET_PING 5
|
||||
#define TCP_PACKET_PONG 4
|
||||
#define TCP_PACKET_OOB_SEND 3
|
||||
#define TCP_PACKET_OOB_RECV 2
|
||||
#define TCP_PACKET_ONION_REQUEST 1
|
||||
#define TCP_PACKET_ONION_RESPONSE 0
|
||||
#else
|
||||
#define TCP_PACKET_ROUTING_REQUEST 0
|
||||
#define TCP_PACKET_ROUTING_RESPONSE 1
|
||||
#define TCP_PACKET_CONNECTION_NOTIFICATION 2
|
||||
#define TCP_PACKET_DISCONNECT_NOTIFICATION 3
|
||||
#define TCP_PACKET_PING 4
|
||||
#define TCP_PACKET_PONG 5
|
||||
#define TCP_PACKET_OOB_SEND 6
|
||||
#define TCP_PACKET_OOB_RECV 7
|
||||
#define TCP_PACKET_ONION_REQUEST 8
|
||||
#define TCP_PACKET_ONION_RESPONSE 9
|
||||
#define TCP_PACKET_FORWARD_REQUEST 10
|
||||
#define TCP_PACKET_FORWARDING 11
|
||||
#endif // test network
|
||||
|
||||
#define TCP_HANDSHAKE_PLAIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE)
|
||||
#define TCP_SERVER_HANDSHAKE_SIZE (CRYPTO_NONCE_SIZE + TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE)
|
||||
#define TCP_CLIENT_HANDSHAKE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + TCP_SERVER_HANDSHAKE_SIZE)
|
||||
#define TCP_MAX_OOB_DATA_LENGTH 1024
|
||||
|
||||
/** frequency to ping connected nodes and timeout in seconds */
|
||||
#define TCP_PING_FREQUENCY 30
|
||||
#define TCP_PING_TIMEOUT 10
|
||||
|
||||
#define MAX_PACKET_SIZE 2048
|
||||
|
||||
typedef struct TCP_Connection {
|
||||
const Random *rng;
|
||||
const Network *ns;
|
||||
Socket sock;
|
||||
IP_Port ip_port; // for debugging.
|
||||
uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */
|
||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||
uint8_t last_packet[2 + MAX_PACKET_SIZE];
|
||||
uint16_t last_packet_length;
|
||||
uint16_t last_packet_sent;
|
||||
|
||||
TCP_Priority_List *priority_queue_start;
|
||||
TCP_Priority_List *priority_queue_end;
|
||||
} TCP_Connection;
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
non_null()
|
||||
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con);
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
non_null()
|
||||
int send_pending_data(const Logger *logger, TCP_Connection *con);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int write_packet_TCP_secure_connection(
|
||||
const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
|
||||
bool priority);
|
||||
|
||||
/** @brief Read length bytes from socket.
|
||||
*
|
||||
* return length on success
|
||||
* return -1 on failure/no data in buffer.
|
||||
*/
|
||||
non_null()
|
||||
int read_TCP_packet(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port);
|
||||
|
||||
/**
|
||||
* @return length of received packet on success.
|
||||
* @retval 0 if could not read any packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int read_packet_TCP_secure_connection(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint16_t *next_packet_length,
|
||||
const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
|
||||
uint16_t max_len, const IP_Port *ip_port);
|
||||
|
||||
#endif
|
1713
external/toxcore/c-toxcore/toxcore/TCP_connection.c
vendored
Normal file
1713
external/toxcore/c-toxcore/toxcore/TCP_connection.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
314
external/toxcore/c-toxcore/toxcore/TCP_connection.h
vendored
Normal file
314
external/toxcore/c-toxcore/toxcore/TCP_connection.h
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles TCP relay connections between two Tox clients.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_CONNECTION_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_CONNECTION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "DHT.h" // for Node_format
|
||||
#include "TCP_client.h"
|
||||
#include "TCP_common.h"
|
||||
|
||||
#define TCP_CONN_NONE 0
|
||||
#define TCP_CONN_VALID 1
|
||||
|
||||
/** NOTE: only used by TCP_con */
|
||||
#define TCP_CONN_CONNECTED 2
|
||||
|
||||
/** Connection is not connected but can be quickly reconnected in case it is needed. */
|
||||
#define TCP_CONN_SLEEPING 3
|
||||
|
||||
#define TCP_CONNECTIONS_STATUS_NONE 0
|
||||
#define TCP_CONNECTIONS_STATUS_REGISTERED 1
|
||||
#define TCP_CONNECTIONS_STATUS_ONLINE 2
|
||||
|
||||
#define MAX_FRIEND_TCP_CONNECTIONS 6
|
||||
|
||||
/** Time until connection to friend gets killed (if it doesn't get locked within that time) */
|
||||
#define TCP_CONNECTION_ANNOUNCE_TIMEOUT TCP_CONNECTION_TIMEOUT
|
||||
|
||||
/** @brief The amount of recommended connections for each friend
|
||||
* NOTE: Must be at most (MAX_FRIEND_TCP_CONNECTIONS / 2)
|
||||
*/
|
||||
#define RECOMMENDED_FRIEND_TCP_CONNECTIONS (MAX_FRIEND_TCP_CONNECTIONS / 2)
|
||||
|
||||
/** Number of TCP connections used for onion purposes. */
|
||||
#define NUM_ONION_TCP_CONNECTIONS RECOMMENDED_FRIEND_TCP_CONNECTIONS
|
||||
|
||||
typedef struct TCP_Conn_to {
|
||||
uint32_t tcp_connection;
|
||||
uint8_t status;
|
||||
uint8_t connection_id;
|
||||
} TCP_Conn_to;
|
||||
|
||||
typedef struct TCP_Connection_to {
|
||||
uint8_t status;
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */
|
||||
|
||||
TCP_Conn_to connections[MAX_FRIEND_TCP_CONNECTIONS];
|
||||
|
||||
int id; /* id used in callbacks. */
|
||||
} TCP_Connection_to;
|
||||
|
||||
typedef struct TCP_con {
|
||||
uint8_t status;
|
||||
TCP_Client_Connection *connection;
|
||||
uint64_t connected_time;
|
||||
uint32_t lock_count;
|
||||
uint32_t sleep_count;
|
||||
bool onion;
|
||||
|
||||
/* Only used when connection is sleeping. */
|
||||
IP_Port ip_port;
|
||||
uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
bool unsleep; /* set to 1 to unsleep connection. */
|
||||
} TCP_con;
|
||||
|
||||
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_count(const TCP_Connections *tcp_c);
|
||||
|
||||
/** @brief Returns the number of connected TCP relays. */
|
||||
non_null()
|
||||
uint32_t tcp_connected_relays_count(const TCP_Connections *tcp_c);
|
||||
|
||||
/** @brief Returns true if we know of a valid TCP relay with the passed public key. */
|
||||
non_null()
|
||||
bool tcp_relay_is_valid(const TCP_Connections *tcp_c, const uint8_t *relay_pk);
|
||||
|
||||
/** @brief Send a packet to the TCP connection.
|
||||
*
|
||||
* return -1 on failure.
|
||||
* return 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int send_packet_tcp_connection(const TCP_Connections *tcp_c, int connections_number, const uint8_t *packet,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Return a TCP connection number for use in send_tcp_onion_request.
|
||||
*
|
||||
* TODO(irungentoo): This number is just the index of an array that the elements
|
||||
* can change without warning.
|
||||
*
|
||||
* return TCP connection number on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int get_random_tcp_onion_conn_number(const TCP_Connections *tcp_c);
|
||||
|
||||
/** @brief Put IP_Port of a random onion TCP connection in ip_port.
|
||||
*
|
||||
* return true on success.
|
||||
* return false on failure.
|
||||
*/
|
||||
non_null()
|
||||
bool tcp_get_random_conn_ip_port(const TCP_Connections *tcp_c, IP_Port *ip_port);
|
||||
|
||||
/** @brief Send an onion packet via the TCP relay corresponding to tcp_connections_number.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Set if we want TCP_connection to allocate some connection for onion use.
|
||||
*
|
||||
* If status is 1, allocate some connections. if status is 0, don't.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_onion_status(TCP_Connections *tcp_c, bool status);
|
||||
|
||||
/**
|
||||
* Send a forward request to the TCP relay with IP_Port tcp_forwarder,
|
||||
* requesting to forward data via a chain of dht nodes starting with dht_node.
|
||||
* A chain_length of 0 means that dht_node is the final destination of data.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_forward_request(const Logger *logger, TCP_Connections *tcp_c, const IP_Port *tcp_forwarder,
|
||||
const IP_Port *dht_node,
|
||||
const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length);
|
||||
|
||||
/** @brief Send an oob packet via the TCP relay corresponding to tcp_connections_number.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_oob_packet(const TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key,
|
||||
const uint8_t *packet, uint16_t length);
|
||||
|
||||
typedef int tcp_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
non_null()
|
||||
int tcp_send_oob_packet_using_relay(const TCP_Connections *tcp_c, const uint8_t *relay_pk, const uint8_t *public_key,
|
||||
const uint8_t *packet, uint16_t length);
|
||||
|
||||
/** @brief Set the callback for TCP data packets. */
|
||||
non_null()
|
||||
void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_data_cb *tcp_data_callback, void *object);
|
||||
|
||||
typedef int tcp_onion_cb(void *object, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/** @brief Set the callback for TCP onion packets. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_onion_cb *tcp_onion_callback, void *object);
|
||||
|
||||
/** @brief Set the callback for TCP forwarding packets. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_forwarding_packet_tcp_connection_callback(TCP_Connections *tcp_c,
|
||||
forwarded_response_cb *tcp_forwarded_response_callback,
|
||||
void *object);
|
||||
|
||||
|
||||
typedef int tcp_oob_cb(void *object, const uint8_t *public_key, unsigned int tcp_connections_number,
|
||||
const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/** @brief Set the callback for TCP oob data packets. */
|
||||
non_null()
|
||||
void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_oob_cb *tcp_oob_callback, void *object);
|
||||
|
||||
/** @brief Encode tcp_connections_number as a custom ip_port.
|
||||
*
|
||||
* return ip_port.
|
||||
*/
|
||||
IP_Port tcp_connections_number_to_ip_port(unsigned int tcp_connections_number);
|
||||
|
||||
/** @brief Decode ip_port created by tcp_connections_number_to_ip_port to tcp_connections_number.
|
||||
*
|
||||
* return true on success.
|
||||
* return false if ip_port is invalid.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_port_to_tcp_connections_number(const IP_Port *ip_port, unsigned int *tcp_connections_number);
|
||||
|
||||
/** @brief Create a new TCP connection to public_key.
|
||||
*
|
||||
* public_key must be the counterpart to the secret key that the other peer used with `new_tcp_connections()`.
|
||||
*
|
||||
* id is the id in the callbacks for that connection.
|
||||
*
|
||||
* return connections_number on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id);
|
||||
|
||||
/**
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number);
|
||||
|
||||
/** @brief Set connection status.
|
||||
*
|
||||
* status of 1 means we are using the connection.
|
||||
* status of 0 means we are not using it.
|
||||
*
|
||||
* Unused tcp connections will be disconnected from but kept in case they are needed.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_connection_to_status(const TCP_Connections *tcp_c, int connections_number, bool status);
|
||||
|
||||
/**
|
||||
* @return number of online tcp relays tied to the connection on success.
|
||||
* @retval 0 on failure.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_connection_to_online_tcp_relays(const TCP_Connections *tcp_c, int connections_number);
|
||||
|
||||
/** @brief Add a TCP relay tied to a connection.
|
||||
*
|
||||
* NOTE: This can only be used during the tcp_oob_callback.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_number_relay_connection(const TCP_Connections *tcp_c, int connections_number,
|
||||
unsigned int tcp_connections_number);
|
||||
|
||||
/** @brief Add a TCP relay tied to a connection.
|
||||
*
|
||||
* This should be called with the same relay by two peers who want to create a TCP connection with each other.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, const IP_Port *ip_port,
|
||||
const uint8_t *relay_pk);
|
||||
|
||||
/** @brief Add a TCP relay to the TCP_Connections instance.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_relay_global(TCP_Connections *tcp_c, const IP_Port *ip_port, const uint8_t *relay_pk);
|
||||
|
||||
/** @brief Copy a maximum of max_num TCP relays we are connected to to tcp_relays.
|
||||
*
|
||||
* NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
|
||||
*
|
||||
* return number of relays copied to tcp_relays on success.
|
||||
* return 0 on failure.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_copy_connected_relays(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num);
|
||||
|
||||
/** @brief Copy a maximum of `max_num` TCP relays we are connected to starting at idx.
|
||||
*
|
||||
* @param idx is the index in the TCP relay array for `tcp_c` designated.
|
||||
* If idx is greater than the array length a modulo operation is performed.
|
||||
*
|
||||
* Returns the number of relays successfully copied.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_copy_connected_relays_index(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num,
|
||||
uint32_t idx);
|
||||
|
||||
/** @brief Returns a new TCP_Connections object associated with the secret_key.
|
||||
*
|
||||
* In order for others to connect to this instance `new_tcp_connection_to()` must be called with the
|
||||
* public_key associated with secret_key.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
non_null()
|
||||
TCP_Connections *new_tcp_connections(
|
||||
const Logger *logger, const Random *rng, const Network *ns, Mono_Time *mono_time,
|
||||
const uint8_t *secret_key, const TCP_Proxy_Info *proxy_info);
|
||||
|
||||
non_null()
|
||||
int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number);
|
||||
|
||||
non_null(1, 2) nullable(3)
|
||||
void do_tcp_connections(const Logger *logger, TCP_Connections *tcp_c, void *userdata);
|
||||
|
||||
nullable(1)
|
||||
void kill_tcp_connections(TCP_Connections *tcp_c);
|
||||
|
||||
#endif
|
10
external/toxcore/c-toxcore/toxcore/TCP_connection_test.cc
vendored
Normal file
10
external/toxcore/c-toxcore/toxcore/TCP_connection_test.cc
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include "TCP_connection.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(Jfreegman) make this useful or remove it after NGC is merged
|
||||
TEST(TCP_connection, NullTest) { (void)tcp_send_oob_packet_using_relay; }
|
||||
|
||||
} // namespace
|
1411
external/toxcore/c-toxcore/toxcore/TCP_server.c
vendored
Normal file
1411
external/toxcore/c-toxcore/toxcore/TCP_server.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
51
external/toxcore/c-toxcore/toxcore/TCP_server.h
vendored
Normal file
51
external/toxcore/c-toxcore/toxcore/TCP_server.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the TCP relay server part of Tox.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_SERVER_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_SERVER_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "forwarding.h"
|
||||
#include "onion.h"
|
||||
|
||||
#define MAX_INCOMING_CONNECTIONS 256
|
||||
|
||||
#define TCP_MAX_BACKLOG MAX_INCOMING_CONNECTIONS
|
||||
|
||||
#define ARRAY_ENTRY_SIZE 6
|
||||
|
||||
typedef enum TCP_Status {
|
||||
TCP_STATUS_NO_STATUS,
|
||||
TCP_STATUS_CONNECTED,
|
||||
TCP_STATUS_UNCONFIRMED,
|
||||
TCP_STATUS_CONFIRMED,
|
||||
} TCP_Status;
|
||||
|
||||
typedef struct TCP_Server TCP_Server;
|
||||
|
||||
non_null()
|
||||
const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server);
|
||||
non_null()
|
||||
size_t tcp_server_listen_count(const TCP_Server *tcp_server);
|
||||
|
||||
/** Create new TCP server instance. */
|
||||
non_null(1, 2, 3, 6, 7) nullable(8, 9)
|
||||
TCP_Server *new_TCP_server(const Logger *logger, const Random *rng, const Network *ns,
|
||||
bool ipv6_enabled, uint16_t num_sockets, const uint16_t *ports,
|
||||
const uint8_t *secret_key, Onion *onion, Forwarding *forwarding);
|
||||
|
||||
/** Run the TCP_server */
|
||||
non_null()
|
||||
void do_TCP_server(TCP_Server *tcp_server, const Mono_Time *mono_time);
|
||||
|
||||
/** Kill the TCP server */
|
||||
nullable(1)
|
||||
void kill_TCP_server(TCP_Server *tcp_server);
|
||||
|
||||
|
||||
#endif
|
700
external/toxcore/c-toxcore/toxcore/announce.c
vendored
Normal file
700
external/toxcore/c-toxcore/toxcore/announce.c
vendored
Normal file
@ -0,0 +1,700 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2020-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* "Server side" of the DHT announcements protocol.
|
||||
*/
|
||||
|
||||
#include "announce.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LAN_discovery.h"
|
||||
#include "ccompat.h"
|
||||
#include "shared_key_cache.h"
|
||||
#include "timed_auth.h"
|
||||
#include "util.h"
|
||||
|
||||
// Settings for the shared key cache
|
||||
#define MAX_KEYS_PER_SLOT 4
|
||||
#define KEYS_TIMEOUT 600
|
||||
|
||||
uint8_t announce_response_of_request_type(uint8_t request_type)
|
||||
{
|
||||
switch (request_type) {
|
||||
case NET_PACKET_DATA_SEARCH_REQUEST:
|
||||
return NET_PACKET_DATA_SEARCH_RESPONSE;
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_REQUEST:
|
||||
return NET_PACKET_DATA_RETRIEVE_RESPONSE;
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_REQUEST:
|
||||
return NET_PACKET_STORE_ANNOUNCE_RESPONSE;
|
||||
|
||||
default: {
|
||||
assert(false);
|
||||
return NET_PACKET_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Announce_Entry {
|
||||
uint64_t store_until;
|
||||
uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
uint8_t *data;
|
||||
uint32_t length;
|
||||
} Announce_Entry;
|
||||
|
||||
struct Announcements {
|
||||
const Logger *log;
|
||||
const Random *rng;
|
||||
Forwarding *forwarding;
|
||||
const Mono_Time *mono_time;
|
||||
DHT *dht;
|
||||
Networking_Core *net;
|
||||
const uint8_t *public_key;
|
||||
const uint8_t *secret_key;
|
||||
|
||||
Shared_Key_Cache *shared_keys;
|
||||
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
||||
|
||||
int32_t synch_offset;
|
||||
|
||||
uint64_t start_time;
|
||||
|
||||
Announce_Entry entries[ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE];
|
||||
};
|
||||
|
||||
void announce_set_synch_offset(Announcements *announce, int32_t synch_offset)
|
||||
{
|
||||
announce->synch_offset = synch_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry is considered to be "deleted" for the purposes of the protocol
|
||||
* once it has timed out.
|
||||
*/
|
||||
non_null()
|
||||
static bool entry_is_empty(const Announcements *announce, const Announce_Entry *entry)
|
||||
{
|
||||
return mono_time_get(announce->mono_time) >= entry->store_until;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void delete_entry(Announce_Entry *entry)
|
||||
{
|
||||
entry->store_until = 0;
|
||||
}
|
||||
|
||||
/** Return bits (at most 8) from pk starting at index as uint8_t */
|
||||
non_null()
|
||||
static uint8_t truncate_pk_at_index(const uint8_t *pk, uint16_t index, uint16_t bits)
|
||||
{
|
||||
assert(bits < 8);
|
||||
const uint8_t i = index / 8;
|
||||
const uint8_t j = index % 8;
|
||||
return ((uint8_t)((i < CRYPTO_PUBLIC_KEY_SIZE ? pk[i] : 0) << j) >> (8 - bits)) |
|
||||
((i + 1 < CRYPTO_PUBLIC_KEY_SIZE ? pk[i + 1] : 0) >> (16 - bits - j));
|
||||
}
|
||||
|
||||
uint16_t announce_get_bucketnum(const uint8_t *base, const uint8_t *pk)
|
||||
{
|
||||
const uint16_t index = bit_by_bit_cmp(base, pk);
|
||||
|
||||
return truncate_pk_at_index(base, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH) ^
|
||||
truncate_pk_at_index(pk, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static Announce_Entry *bucket_of_key(Announcements *announce, const uint8_t *pk)
|
||||
{
|
||||
return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
|
||||
}
|
||||
|
||||
non_null()
|
||||
static Announce_Entry *get_stored(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
return &bucket[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static const Announce_Entry *bucket_of_key_const(const Announcements *announce, const uint8_t *pk)
|
||||
{
|
||||
return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
|
||||
}
|
||||
|
||||
non_null()
|
||||
static const Announce_Entry *get_stored_const(const Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
const Announce_Entry *const bucket = bucket_of_key_const(announce, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
return &bucket[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool announce_on_stored(const Announcements *announce, const uint8_t *data_public_key,
|
||||
announce_on_retrieve_cb *on_retrieve_callback, void *object)
|
||||
{
|
||||
const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr || entry->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (on_retrieve_callback != nullptr) {
|
||||
on_retrieve_callback(object, entry->data, entry->length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return existing entry for this key if it exists, else an empty
|
||||
* slot in the key's bucket if one exists, else an entry in the key's bucket
|
||||
* of greatest 2-adic distance greater than that of the key bucket if one
|
||||
* exists, else nullptr.
|
||||
*/
|
||||
non_null()
|
||||
static Announce_Entry *find_entry_slot(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
|
||||
|
||||
Announce_Entry *slot = nullptr;
|
||||
uint16_t min_index = bit_by_bit_cmp(announce->public_key, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
return &bucket[i];
|
||||
}
|
||||
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
slot = &bucket[i];
|
||||
min_index = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t index = bit_by_bit_cmp(announce->public_key, bucket[i].data_public_key);
|
||||
|
||||
if (index < min_index) {
|
||||
slot = &bucket[i];
|
||||
min_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool would_accept_store_request(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
return find_entry_slot(announce, data_public_key) != nullptr;
|
||||
}
|
||||
|
||||
bool announce_store_data(Announcements *announce, const uint8_t *data_public_key,
|
||||
const uint8_t *data, uint32_t length, uint32_t timeout)
|
||||
{
|
||||
if (length > MAX_ANNOUNCEMENT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Announce_Entry *entry = find_entry_slot(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
assert(data != nullptr);
|
||||
|
||||
if (entry->data != nullptr) {
|
||||
free(entry->data);
|
||||
}
|
||||
|
||||
entry->data = (uint8_t *)malloc(length);
|
||||
|
||||
if (entry->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(entry->data, data, length);
|
||||
}
|
||||
|
||||
entry->length = length;
|
||||
memcpy(entry->data_public_key, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
entry->store_until = mono_time_get(announce->mono_time) + timeout;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint32_t calculate_timeout(const Announcements *announce, uint32_t requested_timeout)
|
||||
{
|
||||
const uint64_t uptime = mono_time_get(announce->mono_time) - announce->start_time;
|
||||
const uint32_t max_announcement_timeout = max_u32(
|
||||
(uint32_t)min_u64(
|
||||
MAX_MAX_ANNOUNCEMENT_TIMEOUT,
|
||||
uptime / MAX_ANNOUNCEMENT_TIMEOUT_UPTIME_RATIO),
|
||||
MIN_MAX_ANNOUNCEMENT_TIMEOUT);
|
||||
|
||||
return min_u32(max_announcement_timeout, requested_timeout);
|
||||
}
|
||||
|
||||
#define DATA_SEARCH_TO_AUTH_MAX_SIZE (CRYPTO_PUBLIC_KEY_SIZE * 2 + MAX_PACKED_IPPORT_SIZE + MAX_SENDBACK_SIZE)
|
||||
|
||||
non_null(1, 2, 3, 4, 7) nullable(5)
|
||||
static int create_data_search_to_auth(const Logger *logger, const uint8_t *data_public_key,
|
||||
const uint8_t *requester_key,
|
||||
const IP_Port *source, const uint8_t *sendback, uint16_t sendback_length,
|
||||
uint8_t *dest, uint16_t max_length)
|
||||
{
|
||||
if (max_length < DATA_SEARCH_TO_AUTH_MAX_SIZE
|
||||
|| sendback_length > MAX_SENDBACK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dest, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE, requester_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
const int ipport_length = pack_ip_port(logger, dest + CRYPTO_PUBLIC_KEY_SIZE * 2, MAX_PACKED_IPPORT_SIZE, source);
|
||||
|
||||
if (ipport_length == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sendback_length > 0) {
|
||||
assert(sendback != nullptr);
|
||||
memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length, sendback, sendback_length);
|
||||
}
|
||||
|
||||
return CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length + sendback_length;
|
||||
}
|
||||
|
||||
#define DATA_SEARCH_TIMEOUT 60
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_data_search_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
if (length != CRYPTO_PUBLIC_KEY_SIZE &&
|
||||
length != CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
const uint8_t *previous_hash = nullptr;
|
||||
|
||||
if (length == CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
|
||||
previous_hash = data + CRYPTO_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
const int nodes_max_length = (int)reply_max_length -
|
||||
(CRYPTO_PUBLIC_KEY_SIZE + 1 + CRYPTO_SHA256_SIZE + TIMED_AUTH_SIZE + 1 + 1);
|
||||
|
||||
if (nodes_max_length < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *p = reply;
|
||||
|
||||
memcpy(p, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
p += CRYPTO_PUBLIC_KEY_SIZE;
|
||||
|
||||
const Announce_Entry *const stored = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (stored == nullptr) {
|
||||
*p = 0;
|
||||
++p;
|
||||
} else {
|
||||
*p = 1;
|
||||
++p;
|
||||
crypto_sha256(p, stored->data, stored->length);
|
||||
p += CRYPTO_SHA256_SIZE;
|
||||
}
|
||||
|
||||
generate_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, p);
|
||||
p += TIMED_AUTH_SIZE;
|
||||
|
||||
*p = would_accept_store_request(announce, data_public_key);
|
||||
++p;
|
||||
|
||||
Node_format nodes_list[MAX_SENT_NODES];
|
||||
const int num_nodes = get_close_nodes(announce->dht, data_public_key, nodes_list,
|
||||
net_family_unspec(), ip_is_lan(&source->ip), true);
|
||||
|
||||
if (num_nodes < 0 || num_nodes > MAX_SENT_NODES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p = num_nodes;
|
||||
++p;
|
||||
|
||||
p += pack_nodes(announce->log, p, nodes_max_length, nodes_list, num_nodes);
|
||||
|
||||
const uint32_t reply_len = p - reply;
|
||||
|
||||
if (previous_hash != nullptr) {
|
||||
uint8_t hash[CRYPTO_SHA256_SIZE];
|
||||
|
||||
crypto_sha256(hash, reply, reply_len);
|
||||
|
||||
if (crypto_sha256_eq(hash, previous_hash)) {
|
||||
return CRYPTO_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_data_retrieve_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
if (length != CRYPTO_PUBLIC_KEY_SIZE + 1 + TIMED_AUTH_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[CRYPTO_PUBLIC_KEY_SIZE] != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
const uint8_t *const auth = data + CRYPTO_PUBLIC_KEY_SIZE + 1;
|
||||
|
||||
if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, auth)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + 1 + entry->length;
|
||||
|
||||
if (reply_max_length < reply_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
reply[CRYPTO_PUBLIC_KEY_SIZE] = 1;
|
||||
memcpy(reply + CRYPTO_PUBLIC_KEY_SIZE + 1, entry->data, entry->length);
|
||||
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_store_announce_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
const int plain_len = (int)length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
|
||||
const int announcement_len = (int)plain_len - (TIMED_AUTH_SIZE + sizeof(uint32_t) + 1);
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
if (announcement_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, plain, plain_len);
|
||||
|
||||
const uint8_t* shared_key = shared_key_cache_lookup(announce->shared_keys, data_public_key);
|
||||
|
||||
if (shared_key == nullptr) {
|
||||
/* Error looking up/deriving the shared key */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (decrypt_data_symmetric(shared_key,
|
||||
data + CRYPTO_PUBLIC_KEY_SIZE,
|
||||
data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
||||
plain_len + CRYPTO_MAC_SIZE,
|
||||
plain) != plain_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const auth = plain;
|
||||
uint32_t requested_timeout;
|
||||
net_unpack_u32(plain + TIMED_AUTH_SIZE, &requested_timeout);
|
||||
const uint32_t timeout = calculate_timeout(announce, requested_timeout);
|
||||
const uint8_t announcement_type = plain[TIMED_AUTH_SIZE + sizeof(uint32_t)];
|
||||
const uint8_t *announcement = plain + TIMED_AUTH_SIZE + sizeof(uint32_t) + 1;
|
||||
|
||||
if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, auth)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announcement_type > 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announcement_type == 1) {
|
||||
if (announcement_len != CRYPTO_SHA256_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Announce_Entry *stored = get_stored(announce, data_public_key);
|
||||
|
||||
if (stored == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t stored_hash[CRYPTO_SHA256_SIZE];
|
||||
crypto_sha256(stored_hash, stored->data, stored->length);
|
||||
|
||||
if (!crypto_sha256_eq(announcement, stored_hash)) {
|
||||
delete_entry(stored);
|
||||
return -1;
|
||||
} else {
|
||||
stored->store_until = mono_time_get(announce->mono_time) + timeout;
|
||||
}
|
||||
} else {
|
||||
if (!announce_store_data(announce, data_public_key, announcement, announcement_len, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint64_t);
|
||||
|
||||
if (reply_max_length < reply_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
net_pack_u32(reply + CRYPTO_PUBLIC_KEY_SIZE, timeout);
|
||||
net_pack_u64(reply + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t),
|
||||
mono_time_get(announce->mono_time) + announce->synch_offset);
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null(1, 2, 3, 7, 9) nullable(5)
|
||||
static int create_reply_plain(Announcements *announce,
|
||||
const uint8_t *requester_key, const IP_Port *source, uint8_t type,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length)
|
||||
{
|
||||
if (length < CRYPTO_PUBLIC_KEY_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
uint8_t to_auth[DATA_SEARCH_TO_AUTH_MAX_SIZE];
|
||||
const int to_auth_length = create_data_search_to_auth(announce->log, data_public_key, requester_key, source,
|
||||
sendback, sendback_length, to_auth, DATA_SEARCH_TO_AUTH_MAX_SIZE);
|
||||
|
||||
if (to_auth_length == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NET_PACKET_DATA_SEARCH_REQUEST:
|
||||
return create_reply_plain_data_search_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_REQUEST:
|
||||
return create_reply_plain_data_retrieve_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_REQUEST:
|
||||
return create_reply_plain_store_announce_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
non_null(1, 2, 5, 7) nullable(3)
|
||||
static int create_reply(Announcements *announce, const IP_Port *source,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length)
|
||||
{
|
||||
const int plain_len = (int)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
|
||||
|
||||
if (plain_len < (int)sizeof(uint64_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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,
|
||||
data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||
data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
||||
plain_len + CRYPTO_MAC_SIZE,
|
||||
plain) != plain_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, plain_reply, plain_reply_max_len);
|
||||
|
||||
const int plain_reply_noping_len = create_reply_plain(announce,
|
||||
data + 1, source, data[0],
|
||||
sendback, sendback_length,
|
||||
plain, plain_len - sizeof(uint64_t),
|
||||
plain_reply, plain_reply_max_len - sizeof(uint64_t));
|
||||
|
||||
if (plain_reply_noping_len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(plain_reply + plain_reply_noping_len,
|
||||
plain + (plain_len - sizeof(uint64_t)), sizeof(uint64_t));
|
||||
|
||||
const uint16_t plain_reply_len = plain_reply_noping_len + sizeof(uint64_t);
|
||||
|
||||
const uint8_t response_type = announce_response_of_request_type(data[0]);
|
||||
|
||||
return dht_create_packet(announce->rng, announce->public_key, shared_key, response_type,
|
||||
plain_reply, plain_reply_len, reply, reply_max_length);
|
||||
}
|
||||
|
||||
non_null(1, 2, 3, 5) nullable(7)
|
||||
static void forwarded_request_callback(void *object, const IP_Port *forwarder,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
Announcements *announce = (Announcements *) object;
|
||||
|
||||
uint8_t reply[MAX_FORWARD_DATA_SIZE];
|
||||
|
||||
const int len = create_reply(announce, forwarder,
|
||||
sendback, sendback_length,
|
||||
data, length, reply, sizeof(reply));
|
||||
|
||||
if (len == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
forward_reply(announce->net, forwarder, sendback, sendback_length, reply, len);
|
||||
}
|
||||
|
||||
non_null(1, 2, 3) nullable(5)
|
||||
static int handle_dht_announce_request(void *object, const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
Announcements *announce = (Announcements *) object;
|
||||
|
||||
uint8_t reply[MAX_FORWARD_DATA_SIZE];
|
||||
|
||||
const int len = create_reply(announce, source,
|
||||
nullptr, 0,
|
||||
data, length, reply, sizeof(reply));
|
||||
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sendpacket(announce->net, source, reply, len) == len ? 0 : -1;
|
||||
}
|
||||
|
||||
Announcements *new_announcements(const Logger *log, const Random *rng, const Mono_Time *mono_time,
|
||||
Forwarding *forwarding)
|
||||
{
|
||||
if (log == nullptr || mono_time == nullptr || forwarding == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Announcements *announce = (Announcements *)calloc(1, sizeof(Announcements));
|
||||
|
||||
if (announce == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
announce->log = log;
|
||||
announce->rng = rng;
|
||||
announce->forwarding = forwarding;
|
||||
announce->mono_time = mono_time;
|
||||
announce->dht = forwarding_get_dht(forwarding);
|
||||
announce->net = dht_get_net(announce->dht);
|
||||
announce->public_key = dht_get_self_public_key(announce->dht);
|
||||
announce->secret_key = dht_get_self_secret_key(announce->dht);
|
||||
new_hmac_key(announce->rng, announce->hmac_key);
|
||||
announce->shared_keys = shared_key_cache_new(mono_time, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||
if (announce->shared_keys == nullptr) {
|
||||
free(announce);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
announce->start_time = mono_time_get(announce->mono_time);
|
||||
|
||||
set_callback_forwarded_request(forwarding, forwarded_request_callback, announce);
|
||||
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, handle_dht_announce_request, announce);
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, handle_dht_announce_request, announce);
|
||||
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, handle_dht_announce_request, announce);
|
||||
|
||||
return announce;
|
||||
}
|
||||
|
||||
void kill_announcements(Announcements *announce)
|
||||
{
|
||||
if (announce == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_callback_forwarded_request(announce->forwarding, nullptr, nullptr);
|
||||
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, nullptr, nullptr);
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, nullptr, nullptr);
|
||||
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
|
||||
|
||||
crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
||||
shared_key_cache_free(announce->shared_keys);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (announce->entries[i].data != nullptr) {
|
||||
free(announce->entries[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
free(announce);
|
||||
}
|
67
external/toxcore/c-toxcore/toxcore/announce.h
vendored
Normal file
67
external/toxcore/c-toxcore/toxcore/announce.h
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2020-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_ANNOUNCE_H
|
||||
#define C_TOXCORE_TOXCORE_ANNOUNCE_H
|
||||
|
||||
#include "forwarding.h"
|
||||
|
||||
#define MAX_ANNOUNCEMENT_SIZE 512
|
||||
|
||||
typedef void announce_on_retrieve_cb(void *object, const uint8_t *data, uint16_t length);
|
||||
|
||||
uint8_t announce_response_of_request_type(uint8_t request_type);
|
||||
|
||||
typedef struct Announcements Announcements;
|
||||
|
||||
non_null()
|
||||
Announcements *new_announcements(const Logger *log, const Random *rng, const Mono_Time *mono_time, Forwarding *forwarding);
|
||||
|
||||
/**
|
||||
* @brief If data is stored, run `on_retrieve_callback` on it.
|
||||
*
|
||||
* @return true if data is stored, false otherwise.
|
||||
*/
|
||||
non_null(1, 2) nullable(3, 4)
|
||||
bool announce_on_stored(const Announcements *announce, const uint8_t *data_public_key,
|
||||
announce_on_retrieve_cb *on_retrieve_callback, void *object);
|
||||
|
||||
non_null()
|
||||
void announce_set_synch_offset(Announcements *announce, int32_t synch_offset);
|
||||
|
||||
nullable(1)
|
||||
void kill_announcements(Announcements *announce);
|
||||
|
||||
|
||||
/* The declarations below are not public, they are exposed only for tests. */
|
||||
|
||||
/** @private
|
||||
* Return xor of first ANNOUNCE_BUCKET_PREFIX_LENGTH bits from one bit after
|
||||
* base and pk first differ
|
||||
*/
|
||||
non_null()
|
||||
uint16_t announce_get_bucketnum(const uint8_t *base, const uint8_t *pk);
|
||||
|
||||
/** @private */
|
||||
non_null(1, 2) nullable(3)
|
||||
bool announce_store_data(Announcements *announce, const uint8_t *data_public_key,
|
||||
const uint8_t *data, uint32_t length, uint32_t timeout);
|
||||
|
||||
/** @private */
|
||||
#define MAX_MAX_ANNOUNCEMENT_TIMEOUT 900
|
||||
#define MIN_MAX_ANNOUNCEMENT_TIMEOUT 10
|
||||
#define MAX_ANNOUNCEMENT_TIMEOUT_UPTIME_RATIO 4
|
||||
|
||||
/** @private
|
||||
* For efficient lookup and updating, entries are stored as a hash table keyed
|
||||
* to the first ANNOUNCE_BUCKET_PREFIX_LENGTH bits starting from one bit after
|
||||
* the first bit in which data public key first differs from the dht key, with
|
||||
* (2-adically) closest keys preferentially stored within a given bucket. A
|
||||
* given key appears at most once (even if timed out).
|
||||
*/
|
||||
#define ANNOUNCE_BUCKET_SIZE 8
|
||||
#define ANNOUNCE_BUCKET_PREFIX_LENGTH 5
|
||||
#define ANNOUNCE_BUCKETS 32 // ANNOUNCE_BUCKETS = 2 ** ANNOUNCE_BUCKET_PREFIX_LENGTH
|
||||
|
||||
#endif
|
31
external/toxcore/c-toxcore/toxcore/attributes.h
vendored
Normal file
31
external/toxcore/c-toxcore/toxcore/attributes.h
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* printf and nonnull attributes for GCC/Clang and Cimple.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
||||
#define C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
||||
|
||||
/* No declarations here. */
|
||||
|
||||
//!TOKSTYLE-
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define GNU_PRINTF(f, a)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(_DEBUG) && !defined(__OPTIMIZE__)
|
||||
#define non_null(...) __attribute__((__nonnull__(__VA_ARGS__)))
|
||||
#else
|
||||
#define non_null(...)
|
||||
#endif
|
||||
|
||||
#define nullable(...)
|
||||
|
||||
//!TOKSTYLE+
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
167
external/toxcore/c-toxcore/toxcore/bin_pack.c
vendored
Normal file
167
external/toxcore/c-toxcore/toxcore/bin_pack.c
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "bin_pack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../third_party/cmp/cmp.h"
|
||||
#include "ccompat.h"
|
||||
|
||||
struct Bin_Pack {
|
||||
uint8_t *bytes;
|
||||
uint32_t bytes_size;
|
||||
uint32_t bytes_pos;
|
||||
cmp_ctx_t ctx;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static bool null_reader(cmp_ctx_t *ctx, void *data, size_t limit)
|
||||
{
|
||||
assert(limit == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool null_skipper(cmp_ctx_t *ctx, size_t limit)
|
||||
{
|
||||
assert(limit == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static size_t buf_writer(cmp_ctx_t *ctx, const void *data, size_t count)
|
||||
{
|
||||
Bin_Pack *bp = (Bin_Pack *)ctx->buf;
|
||||
assert(bp != nullptr);
|
||||
const uint32_t new_pos = bp->bytes_pos + count;
|
||||
if (new_pos < bp->bytes_pos) {
|
||||
// 32 bit overflow.
|
||||
return 0;
|
||||
}
|
||||
if (bp->bytes != nullptr) {
|
||||
if (new_pos > bp->bytes_size) {
|
||||
// Buffer too small.
|
||||
return 0;
|
||||
}
|
||||
memcpy(bp->bytes + bp->bytes_pos, data, count);
|
||||
}
|
||||
bp->bytes_pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
non_null(1) nullable(2)
|
||||
static void bin_pack_init(Bin_Pack *bp, uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
bp->bytes = buf;
|
||||
bp->bytes_size = buf_size;
|
||||
bp->bytes_pos = 0;
|
||||
cmp_init(&bp->ctx, bp, null_reader, null_skipper, buf_writer);
|
||||
}
|
||||
|
||||
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Pack bp;
|
||||
bin_pack_init(&bp, buf, buf_size);
|
||||
return callback(&bp, obj);
|
||||
}
|
||||
|
||||
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj)
|
||||
{
|
||||
Bin_Pack bp;
|
||||
bin_pack_init(&bp, nullptr, 0);
|
||||
callback(&bp, obj);
|
||||
return bp.bytes_pos;
|
||||
}
|
||||
|
||||
Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Pack *bp = (Bin_Pack *)calloc(1, sizeof(Bin_Pack));
|
||||
if (bp == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
bin_pack_init(bp, buf, buf_size);
|
||||
return bp;
|
||||
}
|
||||
|
||||
void bin_pack_free(Bin_Pack *bp)
|
||||
{
|
||||
free(bp);
|
||||
}
|
||||
|
||||
bool bin_pack_array(Bin_Pack *bp, uint32_t size)
|
||||
{
|
||||
return cmp_write_array(&bp->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_pack_bool(Bin_Pack *bp, bool val)
|
||||
{
|
||||
return cmp_write_bool(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u08(Bin_Pack *bp, uint8_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u16(Bin_Pack *bp, uint16_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u32(Bin_Pack *bp, uint32_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u64(Bin_Pack *bp, uint64_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_bin(Bin_Pack *bp, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
return cmp_write_bin(&bp->ctx, data, length);
|
||||
}
|
||||
|
||||
bool bin_pack_nil(Bin_Pack *bp)
|
||||
{
|
||||
return cmp_write_nil(&bp->ctx);
|
||||
}
|
||||
|
||||
bool bin_pack_bin_marker(Bin_Pack *bp, uint32_t size)
|
||||
{
|
||||
return cmp_write_bin_marker(&bp->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_pack_u08_b(Bin_Pack *bp, uint8_t val)
|
||||
{
|
||||
return bp->ctx.write(&bp->ctx, &val, 1) == 1;
|
||||
}
|
||||
|
||||
bool bin_pack_u16_b(Bin_Pack *bp, uint16_t val)
|
||||
{
|
||||
return bin_pack_u08_b(bp, (val >> 8) & 0xff)
|
||||
&& bin_pack_u08_b(bp, val & 0xff);
|
||||
}
|
||||
|
||||
bool bin_pack_u32_b(Bin_Pack *bp, uint32_t val)
|
||||
{
|
||||
return bin_pack_u16_b(bp, (val >> 16) & 0xffff)
|
||||
&& bin_pack_u16_b(bp, val & 0xffff);
|
||||
}
|
||||
|
||||
bool bin_pack_u64_b(Bin_Pack *bp, uint64_t val)
|
||||
{
|
||||
return bin_pack_u32_b(bp, (val >> 32) & 0xffffffff)
|
||||
&& bin_pack_u32_b(bp, val & 0xffffffff);
|
||||
}
|
||||
|
||||
bool bin_pack_bin_b(Bin_Pack *bp, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
return bp->ctx.write(&bp->ctx, data, length) == length;
|
||||
}
|
||||
|
123
external/toxcore/c-toxcore/toxcore/bin_pack.h
vendored
Normal file
123
external/toxcore/c-toxcore/toxcore/bin_pack.h
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_BIN_PACK_H
|
||||
#define C_TOXCORE_TOXCORE_BIN_PACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Binary serialisation object.
|
||||
*/
|
||||
typedef struct Bin_Pack Bin_Pack;
|
||||
|
||||
/** @brief Function used to pack an object.
|
||||
*
|
||||
* This function would typically cast the `void *` to the actual object pointer type and then call
|
||||
* more appropriately typed packing functions.
|
||||
*/
|
||||
typedef bool bin_pack_cb(Bin_Pack *bp, const void *obj);
|
||||
|
||||
/** @brief Determine the serialised size of an object.
|
||||
*
|
||||
* @param callback The function called on the created packer and packed object.
|
||||
* @param obj The object to be packed, passed as `obj` to the callback.
|
||||
*
|
||||
* @return The packed size of the passed object according to the callback. UINT32_MAX in case of
|
||||
* errors such as buffer overflow.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj);
|
||||
|
||||
/** @brief Pack an object into a buffer of a given size.
|
||||
*
|
||||
* This function creates and initialises a `Bin_Pack` packer object, calls the callback with the
|
||||
* packer object and the to-be-packed object, and then cleans up the packer object.
|
||||
*
|
||||
* You can use `bin_pack_obj_size` to determine the minimum required size of `buf`. If packing
|
||||
* overflows `uint32_t`, this function returns `false`.
|
||||
*
|
||||
* @param callback The function called on the created packer and packed object.
|
||||
* @param obj The object to be packed, passed as `obj` to the callback.
|
||||
* @param buf A byte array large enough to hold the serialised representation of `obj`.
|
||||
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
|
||||
*
|
||||
* @retval false if an error occurred (e.g. buffer overflow).
|
||||
*/
|
||||
non_null(1, 3) nullable(2)
|
||||
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Allocate a new packer object.
|
||||
*
|
||||
* This is the only function that allocates memory in this module.
|
||||
*
|
||||
* @param buf A byte array large enough to hold the serialised representation of `obj`.
|
||||
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
|
||||
*
|
||||
* @retval nullptr on allocation failure.
|
||||
*/
|
||||
non_null()
|
||||
Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Deallocates a packer object.
|
||||
*
|
||||
* Does not deallocate the buffer inside.
|
||||
*/
|
||||
nullable(1)
|
||||
void bin_pack_free(Bin_Pack *bp);
|
||||
|
||||
/** @brief Start packing a MessagePack array.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` calls to other functions below.
|
||||
*/
|
||||
non_null()
|
||||
bool bin_pack_array(Bin_Pack *bp, uint32_t size);
|
||||
|
||||
/** @brief Pack a MessagePack bool. */
|
||||
non_null() bool bin_pack_bool(Bin_Pack *bp, bool val);
|
||||
/** @brief Pack a `uint8_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u08(Bin_Pack *bp, uint8_t val);
|
||||
/** @brief Pack a `uint16_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u16(Bin_Pack *bp, uint16_t val);
|
||||
/** @brief Pack a `uint32_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u32(Bin_Pack *bp, uint32_t val);
|
||||
/** @brief Pack a `uint64_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u64(Bin_Pack *bp, uint64_t val);
|
||||
/** @brief Pack an empty array member as a MessagePack nil value. */
|
||||
non_null() bool bin_pack_nil(Bin_Pack *bp);
|
||||
/** @brief Pack a byte array as MessagePack bin. */
|
||||
non_null() bool bin_pack_bin(Bin_Pack *bp, const uint8_t *data, uint32_t length);
|
||||
/** @brief Start packing a custom binary representation.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` bytes packed by functions below.
|
||||
*/
|
||||
non_null() bool bin_pack_bin_marker(Bin_Pack *bp, uint32_t size);
|
||||
|
||||
/** @brief Write a `uint8_t` directly to the packer in 1 byte. */
|
||||
non_null() bool bin_pack_u08_b(Bin_Pack *bp, uint8_t val);
|
||||
/** @brief Write a `uint16_t` as big endian 16 bit int in 2 bytes. */
|
||||
non_null() bool bin_pack_u16_b(Bin_Pack *bp, uint16_t val);
|
||||
/** @brief Write a `uint32_t` as big endian 32 bit int in 4 bytes. */
|
||||
non_null() bool bin_pack_u32_b(Bin_Pack *bp, uint32_t val);
|
||||
/** @brief Write a `uint64_t` as big endian 64 bit int in 8 bytes. */
|
||||
non_null() bool bin_pack_u64_b(Bin_Pack *bp, uint64_t val);
|
||||
|
||||
/** @brief Write a byte array directly to the packer in `length` bytes.
|
||||
*
|
||||
* Note that unless you prepend the array length manually, there is no record of it in the resulting
|
||||
* serialised representation.
|
||||
*/
|
||||
non_null() bool bin_pack_bin_b(Bin_Pack *bp, const uint8_t *data, uint32_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_BIN_PACK_H
|
134
external/toxcore/c-toxcore/toxcore/bin_pack_test.cc
vendored
Normal file
134
external/toxcore/c-toxcore/toxcore/bin_pack_test.cc
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
#include "bin_pack.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "bin_unpack.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Bin_Pack_Deleter {
|
||||
void operator()(Bin_Pack *bp) const { bin_pack_free(bp); }
|
||||
};
|
||||
|
||||
using Bin_Pack_Ptr = std::unique_ptr<Bin_Pack, Bin_Pack_Deleter>;
|
||||
|
||||
struct Bin_Unpack_Deleter {
|
||||
void operator()(Bin_Unpack *bu) const { bin_unpack_free(bu); }
|
||||
};
|
||||
|
||||
using Bin_Unpack_Ptr = std::unique_ptr<Bin_Unpack, Bin_Unpack_Deleter>;
|
||||
|
||||
TEST(BinPack, TooSmallBufferIsNotExceeded)
|
||||
{
|
||||
std::array<uint8_t, 7> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
EXPECT_FALSE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
|
||||
}
|
||||
|
||||
TEST(BinPack, PackedUint64CanBeUnpacked)
|
||||
{
|
||||
std::array<uint8_t, 8> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
uint64_t val;
|
||||
ASSERT_TRUE(bin_unpack_u64_b(bu.get(), &val));
|
||||
EXPECT_EQ(val, 1234567812345678LL);
|
||||
}
|
||||
|
||||
TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
|
||||
{
|
||||
std::array<uint8_t, 2> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_u08(bp.get(), 123));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
uint32_t val;
|
||||
ASSERT_TRUE(bin_unpack_u32(bu.get(), &val));
|
||||
EXPECT_EQ(val, 123);
|
||||
}
|
||||
|
||||
TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
|
||||
{
|
||||
std::array<uint8_t, 2> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_u32(bp.get(), 123));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
uint8_t val;
|
||||
ASSERT_TRUE(bin_unpack_u08(bu.get(), &val));
|
||||
EXPECT_EQ(val, 123);
|
||||
}
|
||||
|
||||
TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8)
|
||||
{
|
||||
std::array<uint8_t, 5> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_u32(bp.get(), 1234567));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
uint8_t val;
|
||||
EXPECT_FALSE(bin_unpack_u08(bu.get(), &val));
|
||||
}
|
||||
|
||||
TEST(BinPack, BinCanHoldPackedInts)
|
||||
{
|
||||
std::array<uint8_t, 12> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_bin_marker(bp.get(), 8));
|
||||
ASSERT_TRUE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
|
||||
ASSERT_TRUE(bin_pack_u16_b(bp.get(), 54321));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
uint32_t size;
|
||||
EXPECT_TRUE(bin_unpack_bin_size(bu.get(), &size));
|
||||
EXPECT_EQ(size, 8);
|
||||
uint64_t val1;
|
||||
EXPECT_TRUE(bin_unpack_u64_b(bu.get(), &val1));
|
||||
EXPECT_EQ(val1, 1234567812345678LL);
|
||||
uint16_t val2;
|
||||
EXPECT_TRUE(bin_unpack_u16_b(bu.get(), &val2));
|
||||
EXPECT_EQ(val2, 54321);
|
||||
}
|
||||
|
||||
TEST(BinPack, BinCanHoldArbitraryData)
|
||||
{
|
||||
std::array<uint8_t, 7> buf;
|
||||
Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bp, nullptr);
|
||||
ASSERT_TRUE(bin_pack_bin_marker(bp.get(), 5));
|
||||
ASSERT_TRUE(bin_pack_bin_b(bp.get(), reinterpret_cast<const uint8_t *>("hello"), 5));
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
ASSERT_NE(bu, nullptr);
|
||||
std::array<uint8_t, 5> str;
|
||||
EXPECT_TRUE(bin_unpack_bin_fixed(bu.get(), str.data(), str.size()));
|
||||
EXPECT_EQ(str, (std::array<uint8_t, 5>{'h', 'e', 'l', 'l', 'o'}));
|
||||
}
|
||||
|
||||
TEST(BinPack, OversizedArrayFailsUnpack)
|
||||
{
|
||||
std::array<uint8_t, 1> buf = {0x91};
|
||||
|
||||
Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
|
||||
uint32_t size;
|
||||
EXPECT_FALSE(bin_unpack_array(bu.get(), &size));
|
||||
}
|
||||
|
||||
} // namespace
|
190
external/toxcore/c-toxcore/toxcore/bin_unpack.c
vendored
Normal file
190
external/toxcore/c-toxcore/toxcore/bin_unpack.c
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "bin_unpack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../third_party/cmp/cmp.h"
|
||||
#include "ccompat.h"
|
||||
|
||||
struct Bin_Unpack {
|
||||
const uint8_t *bytes;
|
||||
uint32_t bytes_size;
|
||||
cmp_ctx_t ctx;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static bool buf_reader(cmp_ctx_t *ctx, void *data, size_t limit)
|
||||
{
|
||||
Bin_Unpack *reader = (Bin_Unpack *)ctx->buf;
|
||||
assert(reader != nullptr && reader->bytes != nullptr);
|
||||
if (limit > reader->bytes_size) {
|
||||
return false;
|
||||
}
|
||||
memcpy(data, reader->bytes, limit);
|
||||
reader->bytes += limit;
|
||||
reader->bytes_size -= limit;
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool buf_skipper(cmp_ctx_t *ctx, size_t limit)
|
||||
{
|
||||
Bin_Unpack *reader = (Bin_Unpack *)ctx->buf;
|
||||
assert(reader != nullptr && reader->bytes != nullptr);
|
||||
if (limit > reader->bytes_size) {
|
||||
return false;
|
||||
}
|
||||
reader->bytes += limit;
|
||||
reader->bytes_size -= limit;
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static size_t null_writer(cmp_ctx_t *ctx, const void *data, size_t count)
|
||||
{
|
||||
assert(count == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Unpack *bu = (Bin_Unpack *)calloc(1, sizeof(Bin_Unpack));
|
||||
if (bu == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
bu->bytes = buf;
|
||||
bu->bytes_size = buf_size;
|
||||
cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer);
|
||||
return bu;
|
||||
}
|
||||
|
||||
void bin_unpack_free(Bin_Unpack *bu)
|
||||
{
|
||||
free(bu);
|
||||
}
|
||||
|
||||
bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size)
|
||||
{
|
||||
return cmp_read_array(&bu->ctx, size) && *size <= bu->bytes_size;
|
||||
}
|
||||
|
||||
bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size)
|
||||
{
|
||||
uint32_t size;
|
||||
return cmp_read_array(&bu->ctx, &size) && size == required_size;
|
||||
}
|
||||
|
||||
bool bin_unpack_bool(Bin_Unpack *bu, bool *val)
|
||||
{
|
||||
return cmp_read_bool(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val)
|
||||
{
|
||||
return cmp_read_uchar(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val)
|
||||
{
|
||||
return cmp_read_ushort(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val)
|
||||
{
|
||||
return cmp_read_uint(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val)
|
||||
{
|
||||
return cmp_read_ulong(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_nil(Bin_Unpack *bu)
|
||||
{
|
||||
return cmp_read_nil(&bu->ctx);
|
||||
}
|
||||
|
||||
bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr)
|
||||
{
|
||||
uint32_t bin_size;
|
||||
if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > bu->bytes_size) {
|
||||
// There aren't as many bytes as this bin claims to want to allocate.
|
||||
return false;
|
||||
}
|
||||
uint8_t *const data = (uint8_t *)malloc(bin_size);
|
||||
|
||||
if (!bin_unpack_bin_b(bu, data, bin_size)) {
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
*data_ptr = data;
|
||||
*data_length_ptr = bin_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
uint32_t bin_size;
|
||||
if (!bin_unpack_bin_size(bu, &bin_size) || bin_size != data_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_bin_b(bu, data, bin_size);
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size)
|
||||
{
|
||||
return cmp_read_bin_size(&bu->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val)
|
||||
{
|
||||
return bin_unpack_bin_b(bu, val, 1);
|
||||
}
|
||||
|
||||
bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val)
|
||||
{
|
||||
uint8_t hi = 0;
|
||||
uint8_t lo = 0;
|
||||
if (!(bin_unpack_u08_b(bu, &hi)
|
||||
&& bin_unpack_u08_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint16_t)hi << 8) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val)
|
||||
{
|
||||
uint16_t hi = 0;
|
||||
uint16_t lo = 0;
|
||||
if (!(bin_unpack_u16_b(bu, &hi)
|
||||
&& bin_unpack_u16_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint32_t)hi << 16) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val)
|
||||
{
|
||||
uint32_t hi = 0;
|
||||
uint32_t lo = 0;
|
||||
if (!(bin_unpack_u32_b(bu, &hi)
|
||||
&& bin_unpack_u32_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint64_t)hi << 32) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length)
|
||||
{
|
||||
return bu->ctx.read(&bu->ctx, data, length);
|
||||
}
|
103
external/toxcore/c-toxcore/toxcore/bin_unpack.h
vendored
Normal file
103
external/toxcore/c-toxcore/toxcore/bin_unpack.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
||||
#define C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Binary deserialisation object.
|
||||
*/
|
||||
typedef struct Bin_Unpack Bin_Unpack;
|
||||
|
||||
/** @brief Allocate a new unpacker object.
|
||||
*
|
||||
* @param buf The byte array to unpack values from.
|
||||
* @param buf_size The size of the byte array.
|
||||
*
|
||||
* @retval nullptr on allocation failure.
|
||||
*/
|
||||
non_null()
|
||||
Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Deallocates an unpacker object.
|
||||
*
|
||||
* Does not deallocate the buffer inside.
|
||||
*/
|
||||
nullable(1)
|
||||
void bin_unpack_free(Bin_Unpack *bu);
|
||||
|
||||
/** @brief Start unpacking a MessagePack array.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` calls to other functions below.
|
||||
*
|
||||
* @param size Will contain the number of array elements following the array marker.
|
||||
*/
|
||||
non_null() bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size);
|
||||
|
||||
/** @brief Start unpacking a fixed size MessagePack array.
|
||||
*
|
||||
* @retval false if the packed array size is not exactly the required size.
|
||||
*/
|
||||
non_null() bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size);
|
||||
|
||||
/** @brief Unpack a MessagePack bool. */
|
||||
non_null() bool bin_unpack_bool(Bin_Unpack *bu, bool *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint8_t`. */
|
||||
non_null() bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint16_t`. */
|
||||
non_null() bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint32_t`. */
|
||||
non_null() bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint64_t`. */
|
||||
non_null() bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val);
|
||||
/** @brief Unpack a Messagepack nil value. */
|
||||
non_null() bool bin_unpack_nil(Bin_Unpack *bu);
|
||||
|
||||
/** @brief Unpack a MessagePack bin into a newly allocated byte array.
|
||||
*
|
||||
* Allocates a new byte array and stores it into `data_ptr` with its length stored in
|
||||
* `data_length_ptr`. This function requires that the unpacking buffer has at least as many bytes
|
||||
* remaining to be unpacked as the bin claims to need, so it's not possible to cause an arbitrarily
|
||||
* large allocation unless the input array was already that large.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr);
|
||||
/** @brief Unpack a MessagePack bin of a fixed length into a pre-allocated byte array.
|
||||
*
|
||||
* Unlike the function above, this function does not allocate any memory, but requires the size to
|
||||
* be known up front.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length);
|
||||
|
||||
/** @brief Start unpacking a custom binary representation.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` bytes packed by functions below.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size);
|
||||
|
||||
/** @brief Read a `uint8_t` directly from the unpacker, consuming 1 byte. */
|
||||
non_null() bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val);
|
||||
/** @brief Read a `uint16_t` as big endian 16 bit int, consuming 2 bytes. */
|
||||
non_null() bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val);
|
||||
/** @brief Read a `uint32_t` as big endian 32 bit int, consuming 4 bytes. */
|
||||
non_null() bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val);
|
||||
/** @brief Read a `uint64_t` as big endian 64 bit int, consuming 8 bytes. */
|
||||
non_null() bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val);
|
||||
|
||||
/** @brief Read a byte array directly from the packer, consuming `length` bytes. */
|
||||
non_null() bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
4
external/toxcore/c-toxcore/toxcore/ccompat.c
vendored
Normal file
4
external/toxcore/c-toxcore/toxcore/ccompat.c
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
#include "ccompat.h"
|
87
external/toxcore/c-toxcore/toxcore/ccompat.h
vendored
Normal file
87
external/toxcore/c-toxcore/toxcore/ccompat.h
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* C language compatibility macros for varying compiler support.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_CCOMPAT_H
|
||||
#define C_TOXCORE_TOXCORE_CCOMPAT_H
|
||||
|
||||
#include <stddef.h> // NULL, size_t
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
//!TOKSTYLE-
|
||||
|
||||
// Variable length arrays.
|
||||
// VLA(type, name, size) allocates a variable length array with automatic
|
||||
// storage duration. VLA_SIZE(name) evaluates to the runtime size of that array
|
||||
// in bytes.
|
||||
//
|
||||
// If C99 VLAs are not available, an emulation using alloca (stack allocation
|
||||
// "function") is used. Note the semantic difference: alloca'd memory does not
|
||||
// get freed at the end of the declaration's scope. Do not use VLA() in loops or
|
||||
// you may run out of stack space.
|
||||
#if !defined(DISABLE_VLA) && !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
// C99 VLAs.
|
||||
#define ALLOC_VLA(type, name, size) type name[size]
|
||||
#define SIZEOF_VLA sizeof
|
||||
#else
|
||||
|
||||
// Emulation using alloca.
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h>
|
||||
#elif defined(__COMPCERT__)
|
||||
// TODO(iphydf): This leaks memory like crazy, so compcert is useless for now.
|
||||
// Once we're rid of VLAs, we can remove this and compcert becomes useful.
|
||||
#define alloca malloc
|
||||
#include <stdlib.h>
|
||||
#elif defined(__linux__)
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#if !defined(alloca) && defined(__GNUC__)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ALLOC_VLA(type, name, size) \
|
||||
const size_t name##_vla_size = (size) * sizeof(type); \
|
||||
type *const name = (type *)alloca(name##_vla_size)
|
||||
#define SIZEOF_VLA(name) name##_vla_size
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MAX_VLA_SIZE
|
||||
#include <assert.h>
|
||||
#define VLA(type, name, size) \
|
||||
ALLOC_VLA(type, name, size); \
|
||||
assert((size_t)(size) * sizeof(type) <= MAX_VLA_SIZE)
|
||||
#else
|
||||
#define VLA ALLOC_VLA
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) || __cplusplus < 201103L
|
||||
#define nullptr NULL
|
||||
#ifndef static_assert
|
||||
#ifdef __GNUC__
|
||||
// We'll just assume gcc and clang support C11 _Static_assert.
|
||||
#define static_assert _Static_assert
|
||||
#else // !__GNUC__
|
||||
#define STATIC_ASSERT_(cond, msg, line) typedef int static_assert_##line[(cond) ? 1 : -1]
|
||||
#define STATIC_ASSERT(cond, msg, line) STATIC_ASSERT_(cond, msg, line)
|
||||
#define static_assert(cond, msg) STATIC_ASSERT(cond, msg, __LINE__)
|
||||
#endif // !__GNUC__
|
||||
#endif // !static_assert
|
||||
#endif // !__cplusplus
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define GNU_PRINTF(f, a)
|
||||
#endif
|
||||
|
||||
//!TOKSTYLE+
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_CCOMPAT_H
|
582
external/toxcore/c-toxcore/toxcore/crypto_core.c
vendored
Normal file
582
external/toxcore/c-toxcore/toxcore/crypto_core.c
vendored
Normal file
@ -0,0 +1,582 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functions for the core crypto.
|
||||
*
|
||||
* NOTE: This code has to be perfect. We don't mess around with encryption.
|
||||
*/
|
||||
#include "crypto_core.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
// We use libsodium by default.
|
||||
#include <sodium.h>
|
||||
#else
|
||||
#include <crypto_auth.h>
|
||||
#include <crypto_box.h>
|
||||
#include <crypto_hash_sha256.h>
|
||||
#include <crypto_hash_sha512.h>
|
||||
#include <crypto_scalarmult_curve25519.h>
|
||||
#include <crypto_verify_16.h>
|
||||
#include <crypto_verify_32.h>
|
||||
#include <randombytes.h>
|
||||
#endif
|
||||
|
||||
#include "ccompat.h"
|
||||
|
||||
#ifndef crypto_box_MACBYTES
|
||||
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
|
||||
#endif
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
// Need dht because of ENC_SECRET_KEY_SIZE and ENC_PUBLIC_KEY_SIZE
|
||||
#define ENC_PUBLIC_KEY_SIZE CRYPTO_PUBLIC_KEY_SIZE
|
||||
#define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE
|
||||
#endif
|
||||
|
||||
static_assert(CRYPTO_PUBLIC_KEY_SIZE == crypto_box_PUBLICKEYBYTES,
|
||||
"CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES");
|
||||
static_assert(CRYPTO_SECRET_KEY_SIZE == crypto_box_SECRETKEYBYTES,
|
||||
"CRYPTO_SECRET_KEY_SIZE should be equal to crypto_box_SECRETKEYBYTES");
|
||||
static_assert(CRYPTO_SHARED_KEY_SIZE == crypto_box_BEFORENMBYTES,
|
||||
"CRYPTO_SHARED_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES");
|
||||
static_assert(CRYPTO_SYMMETRIC_KEY_SIZE == crypto_box_BEFORENMBYTES,
|
||||
"CRYPTO_SYMMETRIC_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES");
|
||||
static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES,
|
||||
"CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES");
|
||||
static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES,
|
||||
"CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES");
|
||||
static_assert(CRYPTO_HMAC_SIZE == crypto_auth_BYTES,
|
||||
"CRYPTO_HMAC_SIZE should be equal to crypto_auth_BYTES");
|
||||
static_assert(CRYPTO_HMAC_KEY_SIZE == crypto_auth_KEYBYTES,
|
||||
"CRYPTO_HMAC_KEY_SIZE should be equal to crypto_auth_KEYBYTES");
|
||||
static_assert(CRYPTO_SHA256_SIZE == crypto_hash_sha256_BYTES,
|
||||
"CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES");
|
||||
static_assert(CRYPTO_SHA512_SIZE == crypto_hash_sha512_BYTES,
|
||||
"CRYPTO_SHA512_SIZE should be equal to crypto_hash_sha512_BYTES");
|
||||
static_assert(CRYPTO_PUBLIC_KEY_SIZE == 32,
|
||||
"CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for pk_equal to work");
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
static_assert(CRYPTO_SIGNATURE_SIZE == crypto_sign_BYTES,
|
||||
"CRYPTO_SIGNATURE_SIZE should be equal to crypto_sign_BYTES");
|
||||
static_assert(CRYPTO_SIGN_PUBLIC_KEY_SIZE == crypto_sign_PUBLICKEYBYTES,
|
||||
"CRYPTO_SIGN_PUBLIC_KEY_SIZE should be equal to crypto_sign_PUBLICKEYBYTES");
|
||||
static_assert(CRYPTO_SIGN_SECRET_KEY_SIZE == crypto_sign_SECRETKEYBYTES,
|
||||
"CRYPTO_SIGN_SECRET_KEY_SIZE should be equal to crypto_sign_SECRETKEYBYTES");
|
||||
#endif /* VANILLA_NACL */
|
||||
|
||||
bool create_extended_keypair(uint8_t *pk, uint8_t *sk)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
/* create signature key pair */
|
||||
crypto_sign_keypair(pk + ENC_PUBLIC_KEY_SIZE, sk + ENC_SECRET_KEY_SIZE);
|
||||
|
||||
/* convert public signature key to public encryption key */
|
||||
const int res1 = crypto_sign_ed25519_pk_to_curve25519(pk, pk + ENC_PUBLIC_KEY_SIZE);
|
||||
|
||||
/* convert secret signature key to secret encryption key */
|
||||
const int res2 = crypto_sign_ed25519_sk_to_curve25519(sk, sk + ENC_SECRET_KEY_SIZE);
|
||||
|
||||
return res1 == 0 && res2 == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint8_t *get_enc_key(const uint8_t *key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
const uint8_t *get_sig_pk(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
void set_sig_pk(uint8_t *key, const uint8_t *sig_pk)
|
||||
{
|
||||
memcpy(key + ENC_PUBLIC_KEY_SIZE, sig_pk, SIG_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
const uint8_t *get_sig_sk(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_SECRET_KEY_SIZE;
|
||||
}
|
||||
|
||||
const uint8_t *get_chat_id(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
static uint8_t *crypto_malloc(size_t bytes)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)malloc(bytes);
|
||||
|
||||
if (ptr != nullptr) {
|
||||
crypto_memlock(ptr, bytes);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
nullable(1)
|
||||
static void crypto_free(uint8_t *ptr, size_t bytes)
|
||||
{
|
||||
if (ptr != nullptr) {
|
||||
crypto_memzero(ptr, bytes);
|
||||
crypto_memunlock(ptr, bytes);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
#endif // !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
|
||||
void crypto_memzero(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
memset(data, 0, length);
|
||||
#else
|
||||
sodium_memzero(data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_memlock(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if (sodium_mlock(data, length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_memunlock(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if (sodium_munlock(data, length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool pk_equal(const uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE])
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(pk1, pk2, CRYPTO_PUBLIC_KEY_SIZE) == 0;
|
||||
#else
|
||||
return crypto_verify_32(pk1, pk2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pk_copy(uint8_t dest[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t src[CRYPTO_PUBLIC_KEY_SIZE])
|
||||
{
|
||||
memcpy(dest, src, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(cksum1, cksum2, CRYPTO_SHA512_SIZE) == 0;
|
||||
#elif defined(VANILLA_NACL)
|
||||
const int lo = crypto_verify_32(cksum1, cksum2) == 0 ? 1 : 0;
|
||||
const int hi = crypto_verify_32(cksum1 + 8, cksum2 + 8) == 0 ? 1 : 0;
|
||||
return (lo & hi) == 1;
|
||||
#else
|
||||
return crypto_verify_64(cksum1, cksum2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(cksum1, cksum2, CRYPTO_SHA256_SIZE) == 0;
|
||||
#else
|
||||
return crypto_verify_32(cksum1, cksum2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t random_u08(const Random *rng)
|
||||
{
|
||||
uint8_t randnum;
|
||||
random_bytes(rng, &randnum, 1);
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint16_t random_u16(const Random *rng)
|
||||
{
|
||||
uint16_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint32_t random_u32(const Random *rng)
|
||||
{
|
||||
uint32_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint64_t random_u64(const Random *rng)
|
||||
{
|
||||
uint64_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint32_t random_range_u32(const Random *rng, uint32_t upper_bound)
|
||||
{
|
||||
return rng->funcs->random_uniform(rng->obj, upper_bound);
|
||||
}
|
||||
|
||||
bool crypto_signature_create(uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *secret_key)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
return crypto_sign_detached(signature, nullptr, message, message_length, secret_key) == 0;
|
||||
#endif // VANILLA_NACL
|
||||
}
|
||||
|
||||
bool crypto_signature_verify(const uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *public_key)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
return crypto_sign_verify_detached(signature, message, message_length, public_key) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool public_key_valid(const uint8_t *public_key)
|
||||
{
|
||||
/* Last bit of key is always zero. */
|
||||
return public_key[31] < 128;
|
||||
}
|
||||
|
||||
int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key,
|
||||
uint8_t *shared_key)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memcpy(shared_key, public_key, CRYPTO_SHARED_KEY_SIZE);
|
||||
return 0;
|
||||
#else
|
||||
return crypto_box_beforenm(shared_key, public_key, secret_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
|
||||
const uint8_t *plain, size_t length, uint8_t *encrypted)
|
||||
{
|
||||
if (length == 0 || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Don't encrypt anything.
|
||||
memcpy(encrypted, plain, length);
|
||||
// Zero MAC to avoid uninitialized memory reads.
|
||||
memset(encrypted + length, 0, crypto_box_MACBYTES);
|
||||
#else
|
||||
|
||||
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);
|
||||
|
||||
if (temp_plain == nullptr || temp_encrypted == nullptr) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// crypto_box_afternm requires the entire range of the output array be
|
||||
// initialised with something. It doesn't matter what it's initialised with,
|
||||
// so we'll pick 0x00.
|
||||
memset(temp_encrypted, 0, size_temp_encrypted);
|
||||
|
||||
memset(temp_plain, 0, crypto_box_ZEROBYTES);
|
||||
// Pad the message with 32 0 bytes.
|
||||
memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length);
|
||||
|
||||
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);
|
||||
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);
|
||||
#endif
|
||||
assert(length < INT32_MAX - crypto_box_MACBYTES);
|
||||
return (int32_t)(length + crypto_box_MACBYTES);
|
||||
}
|
||||
|
||||
int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain)
|
||||
{
|
||||
if (length <= crypto_box_BOXZEROBYTES || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
|
||||
|| plain == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
assert(length >= crypto_box_MACBYTES);
|
||||
memcpy(plain, encrypted, length - crypto_box_MACBYTES); // Don't encrypt anything
|
||||
#else
|
||||
|
||||
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);
|
||||
|
||||
if (temp_plain == nullptr || temp_encrypted == nullptr) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// crypto_box_open_afternm requires the entire range of the output array be
|
||||
// initialised with something. It doesn't matter what it's initialised with,
|
||||
// so we'll pick 0x00.
|
||||
memset(temp_plain, 0, size_temp_plain);
|
||||
|
||||
memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES);
|
||||
// Pad the message with 16 0 bytes.
|
||||
memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length);
|
||||
|
||||
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);
|
||||
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);
|
||||
#endif
|
||||
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, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *plain, size_t length, uint8_t *encrypted)
|
||||
{
|
||||
if (public_key == nullptr || secret_key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t k[crypto_box_BEFORENMBYTES];
|
||||
encrypt_precompute(public_key, secret_key, k);
|
||||
const int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted);
|
||||
crypto_memzero(k, sizeof(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain)
|
||||
{
|
||||
if (public_key == nullptr || secret_key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t k[crypto_box_BEFORENMBYTES];
|
||||
encrypt_precompute(public_key, secret_key, k);
|
||||
const int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain);
|
||||
crypto_memzero(k, sizeof(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void increment_nonce(uint8_t *nonce)
|
||||
{
|
||||
/* TODO(irungentoo): use `increment_nonce_number(nonce, 1)` or
|
||||
* sodium_increment (change to little endian).
|
||||
*
|
||||
* NOTE don't use breaks inside this loop.
|
||||
* In particular, make sure, as far as possible,
|
||||
* that loop bounds and their potential underflow or overflow
|
||||
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
|
||||
*/
|
||||
uint_fast16_t carry = 1U;
|
||||
|
||||
for (uint32_t i = crypto_box_NONCEBYTES; i != 0; --i) {
|
||||
carry += (uint_fast16_t)nonce[i - 1];
|
||||
nonce[i - 1] = (uint8_t)carry;
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void increment_nonce_number(uint8_t *nonce, uint32_t increment)
|
||||
{
|
||||
/* NOTE don't use breaks inside this loop
|
||||
* In particular, make sure, as far as possible,
|
||||
* that loop bounds and their potential underflow or overflow
|
||||
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
|
||||
*/
|
||||
uint8_t num_as_nonce[crypto_box_NONCEBYTES] = {0};
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 4] = increment >> 24;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 3] = increment >> 16;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 2] = increment >> 8;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 1] = increment;
|
||||
|
||||
uint_fast16_t carry = 0U;
|
||||
|
||||
for (uint32_t i = crypto_box_NONCEBYTES; i != 0; --i) {
|
||||
carry += (uint_fast16_t)nonce[i - 1] + (uint_fast16_t)num_as_nonce[i - 1];
|
||||
nonce[i - 1] = (uint8_t)carry;
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void random_nonce(const Random *rng, uint8_t *nonce)
|
||||
{
|
||||
random_bytes(rng, nonce, crypto_box_NONCEBYTES);
|
||||
}
|
||||
|
||||
void new_symmetric_key(const Random *rng, uint8_t *key)
|
||||
{
|
||||
random_bytes(rng, key, CRYPTO_SYMMETRIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
|
||||
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
|
||||
crypto_derive_public_key(public_key, secret_key);
|
||||
return 0;
|
||||
#else
|
||||
return crypto_box_keypair(public_key, secret_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)
|
||||
{
|
||||
crypto_scalarmult_curve25519_base(public_key, secret_key);
|
||||
}
|
||||
|
||||
void new_hmac_key(const Random *rng, uint8_t key[CRYPTO_HMAC_KEY_SIZE])
|
||||
{
|
||||
random_bytes(rng, key, CRYPTO_HMAC_KEY_SIZE);
|
||||
}
|
||||
|
||||
void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data,
|
||||
size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memcpy(auth, key, 16);
|
||||
memcpy(auth + 16, data, length < 16 ? length : 16);
|
||||
#else
|
||||
crypto_auth(auth, data, length, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE],
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
return memcmp(auth, key, 16) == 0 && memcmp(auth + 16, data, length < 16 ? length : 16) == 0;
|
||||
#else
|
||||
return crypto_auth_verify(auth, data, length, key) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memset(hash, 0, CRYPTO_SHA256_SIZE);
|
||||
memcpy(hash, data, length < CRYPTO_SHA256_SIZE ? length : CRYPTO_SHA256_SIZE);
|
||||
#else
|
||||
crypto_hash_sha256(hash, data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memset(hash, 0, CRYPTO_SHA512_SIZE);
|
||||
memcpy(hash, data, length < CRYPTO_SHA512_SIZE ? length : CRYPTO_SHA512_SIZE);
|
||||
#else
|
||||
crypto_hash_sha512(hash, data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void sys_random_bytes(void *obj, uint8_t *bytes, size_t length)
|
||||
{
|
||||
randombytes(bytes, length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint32_t sys_random_uniform(void *obj, uint32_t upper_bound)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
if (upper_bound == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t randnum;
|
||||
sys_random_bytes(obj, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum % upper_bound;
|
||||
#else
|
||||
return randombytes_uniform(upper_bound);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const Random_Funcs system_random_funcs = {
|
||||
sys_random_bytes,
|
||||
sys_random_uniform,
|
||||
};
|
||||
|
||||
static const Random system_random_obj = {&system_random_funcs};
|
||||
|
||||
const Random *system_random(void)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
if ((true)) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
#ifndef VANILLA_NACL
|
||||
// It is safe to call this function more than once and from different
|
||||
// threads -- subsequent calls won't have any effects.
|
||||
if (sodium_init() == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return &system_random_obj;
|
||||
}
|
||||
|
||||
void random_bytes(const Random *rng, uint8_t *bytes, size_t length)
|
||||
{
|
||||
rng->funcs->random_bytes(rng->obj, bytes, length);
|
||||
}
|
452
external/toxcore/c-toxcore/toxcore/crypto_core.h
vendored
Normal file
452
external/toxcore/c-toxcore/toxcore/crypto_core.h
vendored
Normal file
@ -0,0 +1,452 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Functions for the core crypto.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
||||
#define C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The number of bytes in a signature.
|
||||
*/
|
||||
#define CRYPTO_SIGNATURE_SIZE 64
|
||||
|
||||
/**
|
||||
* The number of bytes in a Tox public key used for signatures.
|
||||
*/
|
||||
#define CRYPTO_SIGN_PUBLIC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* The number of bytes in a Tox secret key used for signatures.
|
||||
*/
|
||||
#define CRYPTO_SIGN_SECRET_KEY_SIZE 64
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a Tox public key used for encryption.
|
||||
*/
|
||||
#define CRYPTO_PUBLIC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a Tox secret key used for encryption.
|
||||
*/
|
||||
#define CRYPTO_SECRET_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a shared key computed from public and secret keys.
|
||||
*/
|
||||
#define CRYPTO_SHARED_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a symmetric key.
|
||||
*/
|
||||
#define CRYPTO_SYMMETRIC_KEY_SIZE CRYPTO_SHARED_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes needed for the MAC (message authentication code) in an
|
||||
* encrypted message.
|
||||
*/
|
||||
#define CRYPTO_MAC_SIZE 16
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a nonce used for encryption/decryption.
|
||||
*/
|
||||
#define CRYPTO_NONCE_SIZE 24
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a SHA256 hash.
|
||||
*/
|
||||
#define CRYPTO_SHA256_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a SHA512 hash.
|
||||
*/
|
||||
#define CRYPTO_SHA512_SIZE 64
|
||||
|
||||
typedef void crypto_random_bytes_cb(void *obj, uint8_t *bytes, size_t length);
|
||||
typedef uint32_t crypto_random_uniform_cb(void *obj, uint32_t upper_bound);
|
||||
|
||||
typedef struct Random_Funcs {
|
||||
crypto_random_bytes_cb *random_bytes;
|
||||
crypto_random_uniform_cb *random_uniform;
|
||||
} Random_Funcs;
|
||||
|
||||
typedef struct Random {
|
||||
const Random_Funcs *funcs;
|
||||
void *obj;
|
||||
} Random;
|
||||
|
||||
const Random *system_random(void);
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an encryption public key used by DHT group chats.
|
||||
*/
|
||||
#define ENC_PUBLIC_KEY_SIZE CRYPTO_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an encryption secret key used by DHT group chats.
|
||||
*/
|
||||
#define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a signature public key.
|
||||
*/
|
||||
#define SIG_PUBLIC_KEY_SIZE CRYPTO_SIGN_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a signature secret key.
|
||||
*/
|
||||
#define SIG_SECRET_KEY_SIZE CRYPTO_SIGN_SECRET_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a DHT group chat public key identifier.
|
||||
*/
|
||||
#define CHAT_ID_SIZE SIG_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an extended public key used by DHT group chats.
|
||||
*/
|
||||
#define EXT_PUBLIC_KEY_SIZE (ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an extended secret key used by DHT group chats.
|
||||
*/
|
||||
#define EXT_SECRET_KEY_SIZE (ENC_SECRET_KEY_SIZE + SIG_SECRET_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an HMAC authenticator.
|
||||
*/
|
||||
#define CRYPTO_HMAC_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an HMAC secret key.
|
||||
*/
|
||||
#define CRYPTO_HMAC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief A `bzero`-like function which won't be optimised away by the compiler.
|
||||
*
|
||||
* Some compilers will inline `bzero` or `memset` if they can prove that there
|
||||
* will be no reads to the written data. Use this function if you want to be
|
||||
* sure the memory is indeed zeroed.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_memzero(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute a SHA256 hash (32 bytes).
|
||||
*/
|
||||
non_null()
|
||||
void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute a SHA512 hash (64 bytes).
|
||||
*/
|
||||
non_null()
|
||||
void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute an HMAC authenticator (32 bytes).
|
||||
*
|
||||
* @param auth Resulting authenticator.
|
||||
* @param key Secret key, as generated by `new_hmac_key()`.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data,
|
||||
size_t length);
|
||||
|
||||
/**
|
||||
* @brief Verify an HMAC authenticator.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE],
|
||||
const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 public keys of length @ref CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @retval true if both mem locations of length are equal
|
||||
* @retval false if they are not
|
||||
*/
|
||||
non_null()
|
||||
bool pk_equal(const uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Copy a public key from `src` to `dest`.
|
||||
*/
|
||||
non_null()
|
||||
void pk_copy(uint8_t dest[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t src[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 SHA512 checksums of length CRYPTO_SHA512_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @return true if both mem locations of length are equal, false if they are not.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 SHA256 checksums of length CRYPTO_SHA256_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @return true if both mem locations of length are equal, false if they are not.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2);
|
||||
|
||||
/**
|
||||
* @brief Return a random 8 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint8_t random_u08(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 16 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t random_u16(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 32 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t random_u32(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 64 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint64_t random_u64(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 32 bit integer between 0 and upper_bound (excluded).
|
||||
*
|
||||
* On libsodium builds this function guarantees a uniform distribution of possible outputs.
|
||||
* On vanilla NACL builds this function is equivalent to `random() % upper_bound`.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t random_range_u32(const Random *rng, uint32_t upper_bound);
|
||||
|
||||
/** @brief Cryptographically signs a message using the supplied secret key and puts the resulting signature
|
||||
* in the supplied buffer.
|
||||
*
|
||||
* @param signature The buffer for the resulting signature, which must have room for at
|
||||
* least CRYPTO_SIGNATURE_SIZE bytes.
|
||||
* @param message The message being signed.
|
||||
* @param message_length The length in bytes of the message being signed.
|
||||
* @param secret_key The secret key used to create the signature. The key should be
|
||||
* produced by either `create_extended_keypair` or the libsodium function `crypto_sign_keypair`.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_signature_create(uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *secret_key);
|
||||
|
||||
/** @brief Verifies that the given signature was produced by a given message and public key.
|
||||
*
|
||||
* @param signature The signature we wish to verify.
|
||||
* @param message The message we wish to verify.
|
||||
* @param message_length The length of the message.
|
||||
* @param public_key The public key counterpart of the secret key that was used to
|
||||
* create the signature.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_signature_verify(const uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* @brief Fill the given nonce with random bytes.
|
||||
*/
|
||||
non_null()
|
||||
void random_nonce(const Random *rng, uint8_t *nonce);
|
||||
|
||||
/**
|
||||
* @brief Fill an array of bytes with random values.
|
||||
*/
|
||||
non_null()
|
||||
void random_bytes(const Random *rng, uint8_t *bytes, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not.
|
||||
*
|
||||
* This should only be used for input validation.
|
||||
*
|
||||
* @return false if it isn't, true if it is.
|
||||
*/
|
||||
non_null()
|
||||
bool public_key_valid(const uint8_t *public_key);
|
||||
|
||||
/** @brief Creates an extended keypair: curve25519 and ed25519 for encryption and signing
|
||||
* respectively. The Encryption keys are derived from the signature keys.
|
||||
*
|
||||
* @param pk The buffer where the public key will be stored. Must have room for EXT_PUBLIC_KEY_SIZE bytes.
|
||||
* @param sk The buffer where the secret key will be stored. Must have room for EXT_SECRET_KEY_SIZE bytes.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool create_extended_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
/** Functions for groupchat extended keys */
|
||||
non_null() const uint8_t *get_enc_key(const uint8_t *key);
|
||||
non_null() const uint8_t *get_sig_pk(const uint8_t *key);
|
||||
non_null() void set_sig_pk(uint8_t *key, const uint8_t *sig_pk);
|
||||
non_null() const uint8_t *get_sig_sk(const uint8_t *key);
|
||||
non_null() const uint8_t *get_chat_id(const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Generate a new random keypair.
|
||||
*
|
||||
* Every call to this function is likely to generate a different keypair.
|
||||
*/
|
||||
non_null()
|
||||
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key);
|
||||
|
||||
/**
|
||||
* @brief Derive the public key from a given secret key.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key);
|
||||
|
||||
/**
|
||||
* @brief Encrypt message to send from secret key to public key.
|
||||
*
|
||||
* Encrypt plain text of the given length to encrypted of
|
||||
* `length + CRYPTO_MAC_SIZE` using the public key (@ref CRYPTO_PUBLIC_KEY_SIZE
|
||||
* bytes) of the receiver and the secret key of the sender and a
|
||||
* @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem.
|
||||
* @return length of encrypted data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain,
|
||||
size_t length, uint8_t *encrypted);
|
||||
|
||||
/**
|
||||
* @brief Decrypt message from public key to secret key.
|
||||
*
|
||||
* Decrypt encrypted text of the given @p length to plain text of the given
|
||||
* `length - CRYPTO_MAC_SIZE` using the public key (@ref CRYPTO_PUBLIC_KEY_SIZE
|
||||
* bytes) of the sender, the secret key of the receiver and a
|
||||
* @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem (decryption failed).
|
||||
* @return length of plain text data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain);
|
||||
|
||||
/**
|
||||
* @brief Fast encrypt/decrypt operations.
|
||||
*
|
||||
* Use if this is not a one-time communication. @ref encrypt_precompute does the
|
||||
* shared-key generation once so it does not have to be performed on every
|
||||
* encrypt/decrypt.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key);
|
||||
|
||||
/**
|
||||
* @brief Encrypt message with precomputed shared key.
|
||||
*
|
||||
* Encrypts plain of length length to encrypted of length + @ref CRYPTO_MAC_SIZE
|
||||
* using a shared key @ref CRYPTO_SYMMETRIC_KEY_SIZE big and a @ref CRYPTO_NONCE_SIZE
|
||||
* byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem.
|
||||
* @return length of encrypted data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *plain, size_t length,
|
||||
uint8_t *encrypted);
|
||||
|
||||
/**
|
||||
* @brief Decrypt message with precomputed shared key.
|
||||
*
|
||||
* Decrypts encrypted of length length to plain of length
|
||||
* `length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
|
||||
* big and a @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem (decryption failed).
|
||||
* @return length of plain data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length,
|
||||
uint8_t *plain);
|
||||
|
||||
/**
|
||||
* @brief Increment the given nonce by 1 in big endian (rightmost byte incremented
|
||||
* first).
|
||||
*/
|
||||
non_null()
|
||||
void increment_nonce(uint8_t *nonce);
|
||||
|
||||
/**
|
||||
* @brief Increment the given nonce by a given number.
|
||||
*
|
||||
* The number should be in host byte order.
|
||||
*/
|
||||
non_null()
|
||||
void increment_nonce_number(uint8_t *nonce, uint32_t increment);
|
||||
|
||||
/**
|
||||
* @brief Fill a key @ref CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes.
|
||||
*/
|
||||
non_null()
|
||||
void new_symmetric_key(const Random *rng, uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Locks `length` bytes of memory pointed to by `data`.
|
||||
*
|
||||
* This will attempt to prevent the specified memory region from being swapped
|
||||
* to disk.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_memlock(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Unlocks `length` bytes of memory pointed to by `data`.
|
||||
*
|
||||
* This allows the specified memory region to be swapped to disk.
|
||||
*
|
||||
* This function call has the side effect of zeroing the specified memory region
|
||||
* whether or not it succeeds. Therefore it should only be used once the memory
|
||||
* is no longer in use.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_memunlock(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Generate a random secret HMAC key.
|
||||
*/
|
||||
non_null()
|
||||
void new_hmac_key(const Random *rng, uint8_t key[CRYPTO_HMAC_KEY_SIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
97
external/toxcore/c-toxcore/toxcore/crypto_core_test.cc
vendored
Normal file
97
external/toxcore/c-toxcore/toxcore/crypto_core_test.cc
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
#include "crypto_core.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using HmacKey = std::array<uint8_t, CRYPTO_HMAC_KEY_SIZE>;
|
||||
using Hmac = std::array<uint8_t, CRYPTO_HMAC_SIZE>;
|
||||
using ExtPublicKey = std::array<uint8_t, EXT_PUBLIC_KEY_SIZE>;
|
||||
using ExtSecretKey = std::array<uint8_t, EXT_SECRET_KEY_SIZE>;
|
||||
using Signature = std::array<uint8_t, CRYPTO_SIGNATURE_SIZE>;
|
||||
using Nonce = std::array<uint8_t, CRYPTO_NONCE_SIZE>;
|
||||
|
||||
TEST(CryptoCore, IncrementNonce)
|
||||
{
|
||||
Nonce nonce{};
|
||||
increment_nonce(nonce.data());
|
||||
EXPECT_EQ(
|
||||
nonce, (Nonce{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}));
|
||||
|
||||
for (int i = 0; i < 0x1F4; ++i) {
|
||||
increment_nonce(nonce.data());
|
||||
}
|
||||
|
||||
EXPECT_EQ(nonce,
|
||||
(Nonce{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xF5}}));
|
||||
}
|
||||
|
||||
TEST(CryptoCore, IncrementNonceNumber)
|
||||
{
|
||||
Nonce nonce{};
|
||||
|
||||
increment_nonce_number(nonce.data(), 0x1F5);
|
||||
EXPECT_EQ(nonce,
|
||||
(Nonce{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xF5}}));
|
||||
|
||||
increment_nonce_number(nonce.data(), 0x1F5);
|
||||
EXPECT_EQ(nonce,
|
||||
(Nonce{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0xEA}}));
|
||||
|
||||
increment_nonce_number(nonce.data(), 0x12345678);
|
||||
EXPECT_EQ(nonce,
|
||||
(Nonce{
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x5A, 0x62}}));
|
||||
}
|
||||
|
||||
TEST(CryptoCore, Signatures)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
ExtPublicKey pk;
|
||||
ExtSecretKey sk;
|
||||
|
||||
EXPECT_TRUE(create_extended_keypair(pk.data(), sk.data()));
|
||||
|
||||
std::vector<uint8_t> message;
|
||||
|
||||
// Try a few different sizes, including empty 0 length message.
|
||||
for (uint8_t i = 0; i < 100; ++i) {
|
||||
Signature signature;
|
||||
EXPECT_TRUE(crypto_signature_create(
|
||||
signature.data(), message.data(), message.size(), get_sig_sk(sk.data())));
|
||||
EXPECT_TRUE(crypto_signature_verify(
|
||||
signature.data(), message.data(), message.size(), get_sig_pk(pk.data())));
|
||||
|
||||
message.push_back(random_u08(rng));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CryptoCore, Hmac)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
HmacKey sk;
|
||||
new_hmac_key(rng, sk.data());
|
||||
|
||||
std::vector<uint8_t> message;
|
||||
|
||||
// Try a few different sizes, including empty 0 length message.
|
||||
for (uint8_t i = 0; i < 100; ++i) {
|
||||
Hmac auth;
|
||||
crypto_hmac(auth.data(), sk.data(), message.data(), message.size());
|
||||
EXPECT_TRUE(crypto_hmac_verify(auth.data(), sk.data(), message.data(), message.size()));
|
||||
|
||||
message.push_back(random_u08(rng));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
190
external/toxcore/c-toxcore/toxcore/events/conference_connected.c
vendored
Normal file
190
external/toxcore/c-toxcore/toxcore/events/conference_connected.c
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Connected {
|
||||
uint32_t conference_number;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_connected_construct(Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
*conference_connected = (Tox_Event_Conference_Connected) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_connected_destruct(Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_connected_set_conference_number(
|
||||
Tox_Event_Conference_Connected *conference_connected, uint32_t conference_number)
|
||||
{
|
||||
assert(conference_connected != nullptr);
|
||||
conference_connected->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_connected_get_conference_number(
|
||||
const Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
assert(conference_connected != nullptr);
|
||||
return conference_connected->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_connected_pack(
|
||||
const Tox_Event_Conference_Connected *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_CONNECTED)
|
||||
&& bin_pack_u32(bp, event->conference_number);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_connected_unpack(
|
||||
Tox_Event_Conference_Connected *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_unpack_u32(bu, &event->conference_number);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Connected *tox_events_add_conference_connected(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_connected_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_connected_size == events->conference_connected_capacity) {
|
||||
const uint32_t new_conference_connected_capacity = events->conference_connected_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Connected *new_conference_connected = (Tox_Event_Conference_Connected *)realloc(
|
||||
events->conference_connected, new_conference_connected_capacity * sizeof(Tox_Event_Conference_Connected));
|
||||
|
||||
if (new_conference_connected == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_connected = new_conference_connected;
|
||||
events->conference_connected_capacity = new_conference_connected_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Connected *const conference_connected =
|
||||
&events->conference_connected[events->conference_connected_size];
|
||||
tox_event_conference_connected_construct(conference_connected);
|
||||
++events->conference_connected_size;
|
||||
return conference_connected;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_connected(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_connected_size; ++i) {
|
||||
tox_event_conference_connected_destruct(&events->conference_connected[i]);
|
||||
}
|
||||
|
||||
free(events->conference_connected);
|
||||
events->conference_connected = nullptr;
|
||||
events->conference_connected_size = 0;
|
||||
events->conference_connected_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_connected_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_connected_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Connected *tox_events_get_conference_connected(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_connected_size);
|
||||
assert(events->conference_connected != nullptr);
|
||||
return &events->conference_connected[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_connected(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_connected_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_connected_pack(tox_events_get_conference_connected(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_connected(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Connected *event = tox_events_add_conference_connected(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_connected_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_connected(Tox *tox, uint32_t conference_number, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Connected *conference_connected = tox_events_add_conference_connected(state->events);
|
||||
|
||||
if (conference_connected == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_connected_set_conference_number(conference_connected, conference_number);
|
||||
}
|
249
external/toxcore/c-toxcore/toxcore/events/conference_invite.c
vendored
Normal file
249
external/toxcore/c-toxcore/toxcore/events/conference_invite.c
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Invite {
|
||||
uint32_t friend_number;
|
||||
Tox_Conference_Type type;
|
||||
uint8_t *cookie;
|
||||
uint32_t cookie_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_construct(Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
*conference_invite = (Tox_Event_Conference_Invite) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_invite_destruct(Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
free(conference_invite->cookie);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_set_friend_number(Tox_Event_Conference_Invite *conference_invite,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
conference_invite->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_conference_invite_get_friend_number(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_set_type(Tox_Event_Conference_Invite *conference_invite,
|
||||
Tox_Conference_Type type)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
conference_invite->type = type;
|
||||
}
|
||||
Tox_Conference_Type tox_event_conference_invite_get_type(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_set_cookie(Tox_Event_Conference_Invite *conference_invite,
|
||||
const uint8_t *cookie, uint32_t cookie_length)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
|
||||
if (conference_invite->cookie != nullptr) {
|
||||
free(conference_invite->cookie);
|
||||
conference_invite->cookie = nullptr;
|
||||
conference_invite->cookie_length = 0;
|
||||
}
|
||||
|
||||
conference_invite->cookie = (uint8_t *)malloc(cookie_length);
|
||||
|
||||
if (conference_invite->cookie == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_invite->cookie, cookie, cookie_length);
|
||||
conference_invite->cookie_length = cookie_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_invite_get_cookie_length(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->cookie_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_invite_get_cookie(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->cookie;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_pack(
|
||||
const Tox_Event_Conference_Invite *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_INVITE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->cookie, event->cookie_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_unpack(
|
||||
Tox_Event_Conference_Invite *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_conference_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->cookie, &event->cookie_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Invite *tox_events_add_conference_invite(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_invite_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_invite_size == events->conference_invite_capacity) {
|
||||
const uint32_t new_conference_invite_capacity = events->conference_invite_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Invite *new_conference_invite = (Tox_Event_Conference_Invite *)realloc(
|
||||
events->conference_invite, new_conference_invite_capacity * sizeof(Tox_Event_Conference_Invite));
|
||||
|
||||
if (new_conference_invite == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_invite = new_conference_invite;
|
||||
events->conference_invite_capacity = new_conference_invite_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Invite *const conference_invite = &events->conference_invite[events->conference_invite_size];
|
||||
tox_event_conference_invite_construct(conference_invite);
|
||||
++events->conference_invite_size;
|
||||
return conference_invite;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_invite(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_invite_size; ++i) {
|
||||
tox_event_conference_invite_destruct(&events->conference_invite[i]);
|
||||
}
|
||||
|
||||
free(events->conference_invite);
|
||||
events->conference_invite = nullptr;
|
||||
events->conference_invite_size = 0;
|
||||
events->conference_invite_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_invite_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_invite_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Invite *tox_events_get_conference_invite(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_invite_size);
|
||||
assert(events->conference_invite != nullptr);
|
||||
return &events->conference_invite[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_invite(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_invite_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_invite_pack(tox_events_get_conference_invite(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_invite(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Invite *event = tox_events_add_conference_invite(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_invite_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_invite(Tox *tox, uint32_t friend_number, Tox_Conference_Type type,
|
||||
const uint8_t *cookie, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Invite *conference_invite = tox_events_add_conference_invite(state->events);
|
||||
|
||||
if (conference_invite == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_invite_set_friend_number(conference_invite, friend_number);
|
||||
tox_event_conference_invite_set_type(conference_invite, type);
|
||||
tox_event_conference_invite_set_cookie(conference_invite, cookie, length);
|
||||
}
|
266
external/toxcore/c-toxcore/toxcore/events/conference_message.c
vendored
Normal file
266
external/toxcore/c-toxcore/toxcore/events/conference_message.c
vendored
Normal file
@ -0,0 +1,266 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Message {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_construct(Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
*conference_message = (Tox_Event_Conference_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_message_destruct(Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
free(conference_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_conference_number(Tox_Event_Conference_Message *conference_message,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_conference_number(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_peer_number(Tox_Event_Conference_Message *conference_message,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_peer_number(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_type(Tox_Event_Conference_Message *conference_message,
|
||||
Tox_Message_Type type)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_conference_message_get_type(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_set_message(Tox_Event_Conference_Message *conference_message,
|
||||
const uint8_t *message, uint32_t message_length)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
|
||||
if (conference_message->message != nullptr) {
|
||||
free(conference_message->message);
|
||||
conference_message->message = nullptr;
|
||||
conference_message->message_length = 0;
|
||||
}
|
||||
|
||||
conference_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (conference_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_message->message, message, message_length);
|
||||
conference_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_message_length(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_message_get_message(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_pack(
|
||||
const Tox_Event_Conference_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_MESSAGE)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_unpack(
|
||||
Tox_Event_Conference_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Message *tox_events_add_conference_message(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_message_size == events->conference_message_capacity) {
|
||||
const uint32_t new_conference_message_capacity = events->conference_message_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Message *new_conference_message = (Tox_Event_Conference_Message *)realloc(
|
||||
events->conference_message, new_conference_message_capacity * sizeof(Tox_Event_Conference_Message));
|
||||
|
||||
if (new_conference_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_message = new_conference_message;
|
||||
events->conference_message_capacity = new_conference_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Message *const conference_message = &events->conference_message[events->conference_message_size];
|
||||
tox_event_conference_message_construct(conference_message);
|
||||
++events->conference_message_size;
|
||||
return conference_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_message_size; ++i) {
|
||||
tox_event_conference_message_destruct(&events->conference_message[i]);
|
||||
}
|
||||
|
||||
free(events->conference_message);
|
||||
events->conference_message = nullptr;
|
||||
events->conference_message_size = 0;
|
||||
events->conference_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Message *tox_events_get_conference_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_message_size);
|
||||
assert(events->conference_message != nullptr);
|
||||
return &events->conference_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_message_pack(tox_events_get_conference_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Message *event = tox_events_add_conference_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_message(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
Tox_Message_Type type, const uint8_t *message, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Message *conference_message = tox_events_add_conference_message(state->events);
|
||||
|
||||
if (conference_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_message_set_conference_number(conference_message, conference_number);
|
||||
tox_event_conference_message_set_peer_number(conference_message, peer_number);
|
||||
tox_event_conference_message_set_type(conference_message, type);
|
||||
tox_event_conference_message_set_message(conference_message, message, length);
|
||||
}
|
195
external/toxcore/c-toxcore/toxcore/events/conference_peer_list_changed.c
vendored
Normal file
195
external/toxcore/c-toxcore/toxcore/events/conference_peer_list_changed.c
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Peer_List_Changed {
|
||||
uint32_t conference_number;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_construct(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
*conference_peer_list_changed = (Tox_Event_Conference_Peer_List_Changed) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_destruct(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_set_conference_number(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed, uint32_t conference_number)
|
||||
{
|
||||
assert(conference_peer_list_changed != nullptr);
|
||||
conference_peer_list_changed->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_list_changed_get_conference_number(const Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
assert(conference_peer_list_changed != nullptr);
|
||||
return conference_peer_list_changed->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_list_changed_pack(
|
||||
const Tox_Event_Conference_Peer_List_Changed *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED)
|
||||
&& bin_pack_u32(bp, event->conference_number);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_list_changed_unpack(
|
||||
Tox_Event_Conference_Peer_List_Changed *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_unpack_u32(bu, &event->conference_number);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Peer_List_Changed *tox_events_add_conference_peer_list_changed(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_peer_list_changed_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_peer_list_changed_size == events->conference_peer_list_changed_capacity) {
|
||||
const uint32_t new_conference_peer_list_changed_capacity = events->conference_peer_list_changed_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Peer_List_Changed *new_conference_peer_list_changed = (Tox_Event_Conference_Peer_List_Changed *)
|
||||
realloc(
|
||||
events->conference_peer_list_changed,
|
||||
new_conference_peer_list_changed_capacity * sizeof(Tox_Event_Conference_Peer_List_Changed));
|
||||
|
||||
if (new_conference_peer_list_changed == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_peer_list_changed = new_conference_peer_list_changed;
|
||||
events->conference_peer_list_changed_capacity = new_conference_peer_list_changed_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *const conference_peer_list_changed =
|
||||
&events->conference_peer_list_changed[events->conference_peer_list_changed_size];
|
||||
tox_event_conference_peer_list_changed_construct(conference_peer_list_changed);
|
||||
++events->conference_peer_list_changed_size;
|
||||
return conference_peer_list_changed;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_peer_list_changed(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_peer_list_changed_size; ++i) {
|
||||
tox_event_conference_peer_list_changed_destruct(&events->conference_peer_list_changed[i]);
|
||||
}
|
||||
|
||||
free(events->conference_peer_list_changed);
|
||||
events->conference_peer_list_changed = nullptr;
|
||||
events->conference_peer_list_changed_size = 0;
|
||||
events->conference_peer_list_changed_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_peer_list_changed_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_peer_list_changed_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Peer_List_Changed *tox_events_get_conference_peer_list_changed(const Tox_Events *events,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_peer_list_changed_size);
|
||||
assert(events->conference_peer_list_changed != nullptr);
|
||||
return &events->conference_peer_list_changed[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_peer_list_changed(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_peer_list_changed_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_peer_list_changed_pack(tox_events_get_conference_peer_list_changed(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_peer_list_changed(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Peer_List_Changed *event = tox_events_add_conference_peer_list_changed(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_peer_list_changed_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_peer_list_changed(Tox *tox, uint32_t conference_number, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed = tox_events_add_conference_peer_list_changed(
|
||||
state->events);
|
||||
|
||||
if (conference_peer_list_changed == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_peer_list_changed_set_conference_number(conference_peer_list_changed, conference_number);
|
||||
}
|
250
external/toxcore/c-toxcore/toxcore/events/conference_peer_name.c
vendored
Normal file
250
external/toxcore/c-toxcore/toxcore/events/conference_peer_name.c
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Peer_Name {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_construct(Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
*conference_peer_name = (Tox_Event_Conference_Peer_Name) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_destruct(Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
free(conference_peer_name->name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_set_conference_number(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
conference_peer_name->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_conference_number(const Tox_Event_Conference_Peer_Name
|
||||
*conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_set_peer_number(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
conference_peer_name->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_peer_number(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_set_name(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
const uint8_t *name, uint32_t name_length)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
|
||||
if (conference_peer_name->name != nullptr) {
|
||||
free(conference_peer_name->name);
|
||||
conference_peer_name->name = nullptr;
|
||||
conference_peer_name->name_length = 0;
|
||||
}
|
||||
|
||||
conference_peer_name->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (conference_peer_name->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_peer_name->name, name, name_length);
|
||||
conference_peer_name->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_name_length(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_peer_name_get_name(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_pack(
|
||||
const Tox_Event_Conference_Peer_Name *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_PEER_NAME)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_unpack(
|
||||
Tox_Event_Conference_Peer_Name *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Peer_Name *tox_events_add_conference_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_peer_name_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_peer_name_size == events->conference_peer_name_capacity) {
|
||||
const uint32_t new_conference_peer_name_capacity = events->conference_peer_name_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Peer_Name *new_conference_peer_name = (Tox_Event_Conference_Peer_Name *)realloc(
|
||||
events->conference_peer_name, new_conference_peer_name_capacity * sizeof(Tox_Event_Conference_Peer_Name));
|
||||
|
||||
if (new_conference_peer_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_peer_name = new_conference_peer_name;
|
||||
events->conference_peer_name_capacity = new_conference_peer_name_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_Name *const conference_peer_name =
|
||||
&events->conference_peer_name[events->conference_peer_name_size];
|
||||
tox_event_conference_peer_name_construct(conference_peer_name);
|
||||
++events->conference_peer_name_size;
|
||||
return conference_peer_name;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_peer_name_size; ++i) {
|
||||
tox_event_conference_peer_name_destruct(&events->conference_peer_name[i]);
|
||||
}
|
||||
|
||||
free(events->conference_peer_name);
|
||||
events->conference_peer_name = nullptr;
|
||||
events->conference_peer_name_size = 0;
|
||||
events->conference_peer_name_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_peer_name_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_peer_name_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Peer_Name *tox_events_get_conference_peer_name(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_peer_name_size);
|
||||
assert(events->conference_peer_name != nullptr);
|
||||
return &events->conference_peer_name[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_peer_name(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_peer_name_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_peer_name_pack(tox_events_get_conference_peer_name(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_peer_name(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Peer_Name *event = tox_events_add_conference_peer_name(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_peer_name_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_peer_name(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
const uint8_t *name, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_Name *conference_peer_name = tox_events_add_conference_peer_name(state->events);
|
||||
|
||||
if (conference_peer_name == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_peer_name_set_conference_number(conference_peer_name, conference_number);
|
||||
tox_event_conference_peer_name_set_peer_number(conference_peer_name, peer_number);
|
||||
tox_event_conference_peer_name_set_name(conference_peer_name, name, length);
|
||||
}
|
248
external/toxcore/c-toxcore/toxcore/events/conference_title.c
vendored
Normal file
248
external/toxcore/c-toxcore/toxcore/events/conference_title.c
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Title {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
uint8_t *title;
|
||||
uint32_t title_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_construct(Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
*conference_title = (Tox_Event_Conference_Title) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_title_destruct(Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
free(conference_title->title);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_set_conference_number(Tox_Event_Conference_Title *conference_title,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
conference_title->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_conference_number(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_set_peer_number(Tox_Event_Conference_Title *conference_title,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
conference_title->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_peer_number(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_set_title(Tox_Event_Conference_Title *conference_title, const uint8_t *title,
|
||||
uint32_t title_length)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
|
||||
if (conference_title->title != nullptr) {
|
||||
free(conference_title->title);
|
||||
conference_title->title = nullptr;
|
||||
conference_title->title_length = 0;
|
||||
}
|
||||
|
||||
conference_title->title = (uint8_t *)malloc(title_length);
|
||||
|
||||
if (conference_title->title == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_title->title, title, title_length);
|
||||
conference_title->title_length = title_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_title_length(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->title_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_title_get_title(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->title;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_pack(
|
||||
const Tox_Event_Conference_Title *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_TITLE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_bin(bp, event->title, event->title_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_unpack(
|
||||
Tox_Event_Conference_Title *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& bin_unpack_bin(bu, &event->title, &event->title_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Title *tox_events_add_conference_title(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_title_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_title_size == events->conference_title_capacity) {
|
||||
const uint32_t new_conference_title_capacity = events->conference_title_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Title *new_conference_title = (Tox_Event_Conference_Title *)realloc(
|
||||
events->conference_title, new_conference_title_capacity * sizeof(Tox_Event_Conference_Title));
|
||||
|
||||
if (new_conference_title == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_title = new_conference_title;
|
||||
events->conference_title_capacity = new_conference_title_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Title *const conference_title = &events->conference_title[events->conference_title_size];
|
||||
tox_event_conference_title_construct(conference_title);
|
||||
++events->conference_title_size;
|
||||
return conference_title;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_title(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_title_size; ++i) {
|
||||
tox_event_conference_title_destruct(&events->conference_title[i]);
|
||||
}
|
||||
|
||||
free(events->conference_title);
|
||||
events->conference_title = nullptr;
|
||||
events->conference_title_size = 0;
|
||||
events->conference_title_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_title_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_title_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Title *tox_events_get_conference_title(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_title_size);
|
||||
assert(events->conference_title != nullptr);
|
||||
return &events->conference_title[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_title(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_title_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_title_pack(tox_events_get_conference_title(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_title(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Title *event = tox_events_add_conference_title(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_title_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_title(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
const uint8_t *title, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Title *conference_title = tox_events_add_conference_title(state->events);
|
||||
|
||||
if (conference_title == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_title_set_conference_number(conference_title, conference_number);
|
||||
tox_event_conference_title_set_peer_number(conference_title, peer_number);
|
||||
tox_event_conference_title_set_title(conference_title, title, length);
|
||||
}
|
82
external/toxcore/c-toxcore/toxcore/events/events_alloc.c
vendored
Normal file
82
external/toxcore/c-toxcore/toxcore/events/events_alloc.c
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../ccompat.h"
|
||||
|
||||
Tox_Events_State *tox_events_alloc(void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = (Tox_Events_State *)user_data;
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events != nullptr) {
|
||||
// Already allocated.
|
||||
return state;
|
||||
}
|
||||
|
||||
state->events = (Tox_Events *)calloc(1, sizeof(Tox_Events));
|
||||
|
||||
if (state->events == nullptr) {
|
||||
// It's still null => allocation failed.
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
} else {
|
||||
*state->events = (Tox_Events) {
|
||||
nullptr
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void tox_events_free(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
tox_events_clear_conference_connected(events);
|
||||
tox_events_clear_conference_invite(events);
|
||||
tox_events_clear_conference_message(events);
|
||||
tox_events_clear_conference_peer_list_changed(events);
|
||||
tox_events_clear_conference_peer_name(events);
|
||||
tox_events_clear_conference_title(events);
|
||||
tox_events_clear_file_chunk_request(events);
|
||||
tox_events_clear_file_recv_chunk(events);
|
||||
tox_events_clear_file_recv_control(events);
|
||||
tox_events_clear_file_recv(events);
|
||||
tox_events_clear_friend_connection_status(events);
|
||||
tox_events_clear_friend_lossless_packet(events);
|
||||
tox_events_clear_friend_lossy_packet(events);
|
||||
tox_events_clear_friend_message(events);
|
||||
tox_events_clear_friend_name(events);
|
||||
tox_events_clear_friend_read_receipt(events);
|
||||
tox_events_clear_friend_request(events);
|
||||
tox_events_clear_friend_status(events);
|
||||
tox_events_clear_friend_status_message(events);
|
||||
tox_events_clear_friend_typing(events);
|
||||
tox_events_clear_self_connection_status(events);
|
||||
tox_events_clear_group_peer_name(events);
|
||||
tox_events_clear_group_peer_status(events);
|
||||
tox_events_clear_group_topic(events);
|
||||
tox_events_clear_group_privacy_state(events);
|
||||
tox_events_clear_group_voice_state(events);
|
||||
tox_events_clear_group_topic_lock(events);
|
||||
tox_events_clear_group_peer_limit(events);
|
||||
tox_events_clear_group_password(events);
|
||||
tox_events_clear_group_message(events);
|
||||
tox_events_clear_group_private_message(events);
|
||||
tox_events_clear_group_custom_packet(events);
|
||||
tox_events_clear_group_custom_private_packet(events);
|
||||
tox_events_clear_group_invite(events);
|
||||
tox_events_clear_group_peer_join(events);
|
||||
tox_events_clear_group_peer_exit(events);
|
||||
tox_events_clear_group_self_join(events);
|
||||
tox_events_clear_group_join_fail(events);
|
||||
tox_events_clear_group_moderation(events);
|
||||
free(events);
|
||||
}
|
360
external/toxcore/c-toxcore/toxcore/events/events_alloc.h
vendored
Normal file
360
external/toxcore/c-toxcore/toxcore/events/events_alloc.h
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
||||
#define C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
||||
|
||||
#include "../attributes.h"
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Tox_Events {
|
||||
Tox_Event_Conference_Connected *conference_connected;
|
||||
uint32_t conference_connected_size;
|
||||
uint32_t conference_connected_capacity;
|
||||
|
||||
Tox_Event_Conference_Invite *conference_invite;
|
||||
uint32_t conference_invite_size;
|
||||
uint32_t conference_invite_capacity;
|
||||
|
||||
Tox_Event_Conference_Message *conference_message;
|
||||
uint32_t conference_message_size;
|
||||
uint32_t conference_message_capacity;
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed;
|
||||
uint32_t conference_peer_list_changed_size;
|
||||
uint32_t conference_peer_list_changed_capacity;
|
||||
|
||||
Tox_Event_Conference_Peer_Name *conference_peer_name;
|
||||
uint32_t conference_peer_name_size;
|
||||
uint32_t conference_peer_name_capacity;
|
||||
|
||||
Tox_Event_Conference_Title *conference_title;
|
||||
uint32_t conference_title_size;
|
||||
uint32_t conference_title_capacity;
|
||||
|
||||
Tox_Event_File_Chunk_Request *file_chunk_request;
|
||||
uint32_t file_chunk_request_size;
|
||||
uint32_t file_chunk_request_capacity;
|
||||
|
||||
Tox_Event_File_Recv *file_recv;
|
||||
uint32_t file_recv_size;
|
||||
uint32_t file_recv_capacity;
|
||||
|
||||
Tox_Event_File_Recv_Chunk *file_recv_chunk;
|
||||
uint32_t file_recv_chunk_size;
|
||||
uint32_t file_recv_chunk_capacity;
|
||||
|
||||
Tox_Event_File_Recv_Control *file_recv_control;
|
||||
uint32_t file_recv_control_size;
|
||||
uint32_t file_recv_control_capacity;
|
||||
|
||||
Tox_Event_Friend_Connection_Status *friend_connection_status;
|
||||
uint32_t friend_connection_status_size;
|
||||
uint32_t friend_connection_status_capacity;
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet;
|
||||
uint32_t friend_lossless_packet_size;
|
||||
uint32_t friend_lossless_packet_capacity;
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet;
|
||||
uint32_t friend_lossy_packet_size;
|
||||
uint32_t friend_lossy_packet_capacity;
|
||||
|
||||
Tox_Event_Friend_Message *friend_message;
|
||||
uint32_t friend_message_size;
|
||||
uint32_t friend_message_capacity;
|
||||
|
||||
Tox_Event_Friend_Name *friend_name;
|
||||
uint32_t friend_name_size;
|
||||
uint32_t friend_name_capacity;
|
||||
|
||||
Tox_Event_Friend_Read_Receipt *friend_read_receipt;
|
||||
uint32_t friend_read_receipt_size;
|
||||
uint32_t friend_read_receipt_capacity;
|
||||
|
||||
Tox_Event_Friend_Request *friend_request;
|
||||
uint32_t friend_request_size;
|
||||
uint32_t friend_request_capacity;
|
||||
|
||||
Tox_Event_Friend_Status *friend_status;
|
||||
uint32_t friend_status_size;
|
||||
uint32_t friend_status_capacity;
|
||||
|
||||
Tox_Event_Friend_Status_Message *friend_status_message;
|
||||
uint32_t friend_status_message_size;
|
||||
uint32_t friend_status_message_capacity;
|
||||
|
||||
Tox_Event_Friend_Typing *friend_typing;
|
||||
uint32_t friend_typing_size;
|
||||
uint32_t friend_typing_capacity;
|
||||
|
||||
Tox_Event_Self_Connection_Status *self_connection_status;
|
||||
uint32_t self_connection_status_size;
|
||||
uint32_t self_connection_status_capacity;
|
||||
|
||||
Tox_Event_Group_Peer_Name *group_peer_name;
|
||||
uint32_t group_peer_name_size;
|
||||
uint32_t group_peer_name_capacity;
|
||||
|
||||
Tox_Event_Group_Peer_Status *group_peer_status;
|
||||
uint32_t group_peer_status_size;
|
||||
uint32_t group_peer_status_capacity;
|
||||
|
||||
Tox_Event_Group_Topic *group_topic;
|
||||
uint32_t group_topic_size;
|
||||
uint32_t group_topic_capacity;
|
||||
|
||||
Tox_Event_Group_Privacy_State *group_privacy_state;
|
||||
uint32_t group_privacy_state_size;
|
||||
uint32_t group_privacy_state_capacity;
|
||||
|
||||
Tox_Event_Group_Voice_State *group_voice_state;
|
||||
uint32_t group_voice_state_size;
|
||||
uint32_t group_voice_state_capacity;
|
||||
|
||||
Tox_Event_Group_Topic_Lock *group_topic_lock;
|
||||
uint32_t group_topic_lock_size;
|
||||
uint32_t group_topic_lock_capacity;
|
||||
|
||||
Tox_Event_Group_Peer_Limit *group_peer_limit;
|
||||
uint32_t group_peer_limit_size;
|
||||
uint32_t group_peer_limit_capacity;
|
||||
|
||||
Tox_Event_Group_Password *group_password;
|
||||
uint32_t group_password_size;
|
||||
uint32_t group_password_capacity;
|
||||
|
||||
Tox_Event_Group_Message *group_message;
|
||||
uint32_t group_message_size;
|
||||
uint32_t group_message_capacity;
|
||||
|
||||
Tox_Event_Group_Private_Message *group_private_message;
|
||||
uint32_t group_private_message_size;
|
||||
uint32_t group_private_message_capacity;
|
||||
|
||||
Tox_Event_Group_Custom_Packet *group_custom_packet;
|
||||
uint32_t group_custom_packet_size;
|
||||
uint32_t group_custom_packet_capacity;
|
||||
|
||||
Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet;
|
||||
uint32_t group_custom_private_packet_size;
|
||||
uint32_t group_custom_private_packet_capacity;
|
||||
|
||||
Tox_Event_Group_Invite *group_invite;
|
||||
uint32_t group_invite_size;
|
||||
uint32_t group_invite_capacity;
|
||||
|
||||
Tox_Event_Group_Peer_Join *group_peer_join;
|
||||
uint32_t group_peer_join_size;
|
||||
uint32_t group_peer_join_capacity;
|
||||
|
||||
Tox_Event_Group_Peer_Exit *group_peer_exit;
|
||||
uint32_t group_peer_exit_size;
|
||||
uint32_t group_peer_exit_capacity;
|
||||
|
||||
Tox_Event_Group_Self_Join *group_self_join;
|
||||
uint32_t group_self_join_size;
|
||||
uint32_t group_self_join_capacity;
|
||||
|
||||
Tox_Event_Group_Join_Fail *group_join_fail;
|
||||
uint32_t group_join_fail_size;
|
||||
uint32_t group_join_fail_capacity;
|
||||
|
||||
Tox_Event_Group_Moderation *group_moderation;
|
||||
uint32_t group_moderation_size;
|
||||
uint32_t group_moderation_capacity;
|
||||
};
|
||||
|
||||
typedef struct Tox_Events_State {
|
||||
Tox_Err_Events_Iterate error;
|
||||
Tox_Events *events;
|
||||
} Tox_Events_State;
|
||||
|
||||
tox_conference_connected_cb tox_events_handle_conference_connected;
|
||||
tox_conference_invite_cb tox_events_handle_conference_invite;
|
||||
tox_conference_message_cb tox_events_handle_conference_message;
|
||||
tox_conference_peer_list_changed_cb tox_events_handle_conference_peer_list_changed;
|
||||
tox_conference_peer_name_cb tox_events_handle_conference_peer_name;
|
||||
tox_conference_title_cb tox_events_handle_conference_title;
|
||||
tox_file_chunk_request_cb tox_events_handle_file_chunk_request;
|
||||
tox_file_recv_cb tox_events_handle_file_recv;
|
||||
tox_file_recv_chunk_cb tox_events_handle_file_recv_chunk;
|
||||
tox_file_recv_control_cb tox_events_handle_file_recv_control;
|
||||
tox_friend_connection_status_cb tox_events_handle_friend_connection_status;
|
||||
tox_friend_lossless_packet_cb tox_events_handle_friend_lossless_packet;
|
||||
tox_friend_lossy_packet_cb tox_events_handle_friend_lossy_packet;
|
||||
tox_friend_message_cb tox_events_handle_friend_message;
|
||||
tox_friend_name_cb tox_events_handle_friend_name;
|
||||
tox_friend_read_receipt_cb tox_events_handle_friend_read_receipt;
|
||||
tox_friend_request_cb tox_events_handle_friend_request;
|
||||
tox_friend_status_cb tox_events_handle_friend_status;
|
||||
tox_friend_status_message_cb tox_events_handle_friend_status_message;
|
||||
tox_friend_typing_cb tox_events_handle_friend_typing;
|
||||
tox_self_connection_status_cb tox_events_handle_self_connection_status;
|
||||
tox_group_peer_name_cb tox_events_handle_group_peer_name;
|
||||
tox_group_peer_status_cb tox_events_handle_group_peer_status;
|
||||
tox_group_topic_cb tox_events_handle_group_topic;
|
||||
tox_group_privacy_state_cb tox_events_handle_group_privacy_state;
|
||||
tox_group_voice_state_cb tox_events_handle_group_voice_state;
|
||||
tox_group_topic_lock_cb tox_events_handle_group_topic_lock;
|
||||
tox_group_peer_limit_cb tox_events_handle_group_peer_limit;
|
||||
tox_group_password_cb tox_events_handle_group_password;
|
||||
tox_group_message_cb tox_events_handle_group_message;
|
||||
tox_group_private_message_cb tox_events_handle_group_private_message;
|
||||
tox_group_custom_packet_cb tox_events_handle_group_custom_packet;
|
||||
tox_group_custom_private_packet_cb tox_events_handle_group_custom_private_packet;
|
||||
tox_group_invite_cb tox_events_handle_group_invite;
|
||||
tox_group_peer_join_cb tox_events_handle_group_peer_join;
|
||||
tox_group_peer_exit_cb tox_events_handle_group_peer_exit;
|
||||
tox_group_self_join_cb tox_events_handle_group_self_join;
|
||||
tox_group_join_fail_cb tox_events_handle_group_join_fail;
|
||||
tox_group_moderation_cb tox_events_handle_group_moderation;
|
||||
|
||||
// non_null()
|
||||
typedef void tox_events_clear_cb(Tox_Events *events);
|
||||
|
||||
tox_events_clear_cb tox_events_clear_conference_connected;
|
||||
tox_events_clear_cb tox_events_clear_conference_invite;
|
||||
tox_events_clear_cb tox_events_clear_conference_message;
|
||||
tox_events_clear_cb tox_events_clear_conference_peer_list_changed;
|
||||
tox_events_clear_cb tox_events_clear_conference_peer_name;
|
||||
tox_events_clear_cb tox_events_clear_conference_title;
|
||||
tox_events_clear_cb tox_events_clear_file_chunk_request;
|
||||
tox_events_clear_cb tox_events_clear_file_recv_chunk;
|
||||
tox_events_clear_cb tox_events_clear_file_recv_control;
|
||||
tox_events_clear_cb tox_events_clear_file_recv;
|
||||
tox_events_clear_cb tox_events_clear_friend_connection_status;
|
||||
tox_events_clear_cb tox_events_clear_friend_lossless_packet;
|
||||
tox_events_clear_cb tox_events_clear_friend_lossy_packet;
|
||||
tox_events_clear_cb tox_events_clear_friend_message;
|
||||
tox_events_clear_cb tox_events_clear_friend_name;
|
||||
tox_events_clear_cb tox_events_clear_friend_read_receipt;
|
||||
tox_events_clear_cb tox_events_clear_friend_request;
|
||||
tox_events_clear_cb tox_events_clear_friend_status_message;
|
||||
tox_events_clear_cb tox_events_clear_friend_status;
|
||||
tox_events_clear_cb tox_events_clear_friend_typing;
|
||||
tox_events_clear_cb tox_events_clear_self_connection_status;
|
||||
tox_events_clear_cb tox_events_clear_group_peer_name;
|
||||
tox_events_clear_cb tox_events_clear_group_peer_status;
|
||||
tox_events_clear_cb tox_events_clear_group_topic;
|
||||
tox_events_clear_cb tox_events_clear_group_privacy_state;
|
||||
tox_events_clear_cb tox_events_clear_group_voice_state;
|
||||
tox_events_clear_cb tox_events_clear_group_topic_lock;
|
||||
tox_events_clear_cb tox_events_clear_group_peer_limit;
|
||||
tox_events_clear_cb tox_events_clear_group_password;
|
||||
tox_events_clear_cb tox_events_clear_group_message;
|
||||
tox_events_clear_cb tox_events_clear_group_private_message;
|
||||
tox_events_clear_cb tox_events_clear_group_custom_packet;
|
||||
tox_events_clear_cb tox_events_clear_group_custom_private_packet;
|
||||
tox_events_clear_cb tox_events_clear_group_invite;
|
||||
tox_events_clear_cb tox_events_clear_group_peer_join;
|
||||
tox_events_clear_cb tox_events_clear_group_peer_exit;
|
||||
tox_events_clear_cb tox_events_clear_group_self_join;
|
||||
tox_events_clear_cb tox_events_clear_group_join_fail;
|
||||
tox_events_clear_cb tox_events_clear_group_moderation;
|
||||
|
||||
// non_null()
|
||||
typedef bool tox_events_pack_cb(const Tox_Events *events, Bin_Pack *bp);
|
||||
|
||||
tox_events_pack_cb tox_events_pack_conference_connected;
|
||||
tox_events_pack_cb tox_events_pack_conference_invite;
|
||||
tox_events_pack_cb tox_events_pack_conference_message;
|
||||
tox_events_pack_cb tox_events_pack_conference_peer_list_changed;
|
||||
tox_events_pack_cb tox_events_pack_conference_peer_name;
|
||||
tox_events_pack_cb tox_events_pack_conference_title;
|
||||
tox_events_pack_cb tox_events_pack_file_chunk_request;
|
||||
tox_events_pack_cb tox_events_pack_file_recv_chunk;
|
||||
tox_events_pack_cb tox_events_pack_file_recv_control;
|
||||
tox_events_pack_cb tox_events_pack_file_recv;
|
||||
tox_events_pack_cb tox_events_pack_friend_connection_status;
|
||||
tox_events_pack_cb tox_events_pack_friend_lossless_packet;
|
||||
tox_events_pack_cb tox_events_pack_friend_lossy_packet;
|
||||
tox_events_pack_cb tox_events_pack_friend_message;
|
||||
tox_events_pack_cb tox_events_pack_friend_name;
|
||||
tox_events_pack_cb tox_events_pack_friend_read_receipt;
|
||||
tox_events_pack_cb tox_events_pack_friend_request;
|
||||
tox_events_pack_cb tox_events_pack_friend_status_message;
|
||||
tox_events_pack_cb tox_events_pack_friend_status;
|
||||
tox_events_pack_cb tox_events_pack_friend_typing;
|
||||
tox_events_pack_cb tox_events_pack_self_connection_status;
|
||||
tox_events_pack_cb tox_events_pack_group_peer_name;
|
||||
tox_events_pack_cb tox_events_pack_group_peer_status;
|
||||
tox_events_pack_cb tox_events_pack_group_topic;
|
||||
tox_events_pack_cb tox_events_pack_group_privacy_state;
|
||||
tox_events_pack_cb tox_events_pack_group_voice_state;
|
||||
tox_events_pack_cb tox_events_pack_group_topic_lock;
|
||||
tox_events_pack_cb tox_events_pack_group_peer_limit;
|
||||
tox_events_pack_cb tox_events_pack_group_password;
|
||||
tox_events_pack_cb tox_events_pack_group_message;
|
||||
tox_events_pack_cb tox_events_pack_group_private_message;
|
||||
tox_events_pack_cb tox_events_pack_group_custom_packet;
|
||||
tox_events_pack_cb tox_events_pack_group_custom_private_packet;
|
||||
tox_events_pack_cb tox_events_pack_group_invite;
|
||||
tox_events_pack_cb tox_events_pack_group_peer_join;
|
||||
tox_events_pack_cb tox_events_pack_group_peer_exit;
|
||||
tox_events_pack_cb tox_events_pack_group_self_join;
|
||||
tox_events_pack_cb tox_events_pack_group_join_fail;
|
||||
tox_events_pack_cb tox_events_pack_group_moderation;
|
||||
|
||||
tox_events_pack_cb tox_events_pack;
|
||||
|
||||
// non_null()
|
||||
typedef bool tox_events_unpack_cb(Tox_Events *events, Bin_Unpack *bu);
|
||||
|
||||
tox_events_unpack_cb tox_events_unpack_conference_connected;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_invite;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_message;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_peer_list_changed;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_peer_name;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_title;
|
||||
tox_events_unpack_cb tox_events_unpack_file_chunk_request;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv_chunk;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv_control;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_connection_status;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_lossless_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_lossy_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_message;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_name;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_read_receipt;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_request;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_status_message;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_status;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_typing;
|
||||
tox_events_unpack_cb tox_events_unpack_self_connection_status;
|
||||
tox_events_unpack_cb tox_events_unpack_group_peer_name;
|
||||
tox_events_unpack_cb tox_events_unpack_group_peer_status;
|
||||
tox_events_unpack_cb tox_events_unpack_group_topic;
|
||||
tox_events_unpack_cb tox_events_unpack_group_privacy_state;
|
||||
tox_events_unpack_cb tox_events_unpack_group_voice_state;
|
||||
tox_events_unpack_cb tox_events_unpack_group_topic_lock;
|
||||
tox_events_unpack_cb tox_events_unpack_group_peer_limit;
|
||||
tox_events_unpack_cb tox_events_unpack_group_password;
|
||||
tox_events_unpack_cb tox_events_unpack_group_message;
|
||||
tox_events_unpack_cb tox_events_unpack_group_private_message;
|
||||
tox_events_unpack_cb tox_events_unpack_group_custom_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_group_custom_private_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_group_invite;
|
||||
tox_events_unpack_cb tox_events_unpack_group_peer_join;
|
||||
tox_events_unpack_cb tox_events_unpack_group_peer_exit;
|
||||
tox_events_unpack_cb tox_events_unpack_group_self_join;
|
||||
tox_events_unpack_cb tox_events_unpack_group_join_fail;
|
||||
tox_events_unpack_cb tox_events_unpack_group_moderation;
|
||||
|
||||
tox_events_unpack_cb tox_events_unpack;
|
||||
|
||||
non_null()
|
||||
Tox_Events_State *tox_events_alloc(void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
243
external/toxcore/c-toxcore/toxcore/events/file_chunk_request.c
vendored
Normal file
243
external/toxcore/c-toxcore/toxcore/events/file_chunk_request.c
vendored
Normal file
@ -0,0 +1,243 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Chunk_Request {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint64_t position;
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_construct(Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
*file_chunk_request = (Tox_Event_File_Chunk_Request) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_destruct(Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_friend_number(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_chunk_request_get_friend_number(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_file_number(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_chunk_request_get_file_number(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_position(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint64_t position)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->position = position;
|
||||
}
|
||||
uint64_t tox_event_file_chunk_request_get_position(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->position;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_length(Tox_Event_File_Chunk_Request *file_chunk_request, uint16_t length)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->length = length;
|
||||
}
|
||||
uint16_t tox_event_file_chunk_request_get_length(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->length;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_chunk_request_pack(
|
||||
const Tox_Event_File_Chunk_Request *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_CHUNK_REQUEST)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u64(bp, event->position)
|
||||
&& bin_pack_u16(bp, event->length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_chunk_request_unpack(
|
||||
Tox_Event_File_Chunk_Request *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u64(bu, &event->position)
|
||||
&& bin_unpack_u16(bu, &event->length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Chunk_Request *tox_events_add_file_chunk_request(Tox_Events *events)
|
||||
{
|
||||
if (events->file_chunk_request_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_chunk_request_size == events->file_chunk_request_capacity) {
|
||||
const uint32_t new_file_chunk_request_capacity = events->file_chunk_request_capacity * 2 + 1;
|
||||
Tox_Event_File_Chunk_Request *new_file_chunk_request = (Tox_Event_File_Chunk_Request *)realloc(
|
||||
events->file_chunk_request, new_file_chunk_request_capacity * sizeof(Tox_Event_File_Chunk_Request));
|
||||
|
||||
if (new_file_chunk_request == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_chunk_request = new_file_chunk_request;
|
||||
events->file_chunk_request_capacity = new_file_chunk_request_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Chunk_Request *const file_chunk_request = &events->file_chunk_request[events->file_chunk_request_size];
|
||||
tox_event_file_chunk_request_construct(file_chunk_request);
|
||||
++events->file_chunk_request_size;
|
||||
return file_chunk_request;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_chunk_request(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_chunk_request_size; ++i) {
|
||||
tox_event_file_chunk_request_destruct(&events->file_chunk_request[i]);
|
||||
}
|
||||
|
||||
free(events->file_chunk_request);
|
||||
events->file_chunk_request = nullptr;
|
||||
events->file_chunk_request_size = 0;
|
||||
events->file_chunk_request_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_chunk_request_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_chunk_request_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Chunk_Request *tox_events_get_file_chunk_request(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_chunk_request_size);
|
||||
assert(events->file_chunk_request != nullptr);
|
||||
return &events->file_chunk_request[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_chunk_request(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_chunk_request_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_chunk_request_pack(tox_events_get_file_chunk_request(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_chunk_request(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Chunk_Request *event = tox_events_add_file_chunk_request(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_chunk_request_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Chunk_Request *file_chunk_request = tox_events_add_file_chunk_request(state->events);
|
||||
|
||||
if (file_chunk_request == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_chunk_request_set_friend_number(file_chunk_request, friend_number);
|
||||
tox_event_file_chunk_request_set_file_number(file_chunk_request, file_number);
|
||||
tox_event_file_chunk_request_set_position(file_chunk_request, position);
|
||||
tox_event_file_chunk_request_set_length(file_chunk_request, length);
|
||||
}
|
282
external/toxcore/c-toxcore/toxcore/events/file_recv.c
vendored
Normal file
282
external/toxcore/c-toxcore/toxcore/events/file_recv.c
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint32_t kind;
|
||||
uint64_t file_size;
|
||||
uint8_t *filename;
|
||||
uint32_t filename_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_construct(Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
*file_recv = (Tox_Event_File_Recv) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_destruct(Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
free(file_recv->filename);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_friend_number(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_friend_number(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_file_number(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_file_number(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_kind(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t kind)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->kind = kind;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_kind(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->kind;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_file_size(Tox_Event_File_Recv *file_recv,
|
||||
uint64_t file_size)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->file_size = file_size;
|
||||
}
|
||||
uint64_t tox_event_file_recv_get_file_size(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->file_size;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_set_filename(Tox_Event_File_Recv *file_recv, const uint8_t *filename,
|
||||
uint32_t filename_length)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
|
||||
if (file_recv->filename != nullptr) {
|
||||
free(file_recv->filename);
|
||||
file_recv->filename = nullptr;
|
||||
file_recv->filename_length = 0;
|
||||
}
|
||||
|
||||
file_recv->filename = (uint8_t *)malloc(filename_length);
|
||||
|
||||
if (file_recv->filename == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(file_recv->filename, filename, filename_length);
|
||||
file_recv->filename_length = filename_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_filename_length(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->filename_length;
|
||||
}
|
||||
const uint8_t *tox_event_file_recv_get_filename(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->filename;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_pack(
|
||||
const Tox_Event_File_Recv *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV)
|
||||
&& bin_pack_array(bp, 5)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u32(bp, event->kind)
|
||||
&& bin_pack_u64(bp, event->file_size)
|
||||
&& bin_pack_bin(bp, event->filename, event->filename_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_unpack(
|
||||
Tox_Event_File_Recv *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u32(bu, &event->kind)
|
||||
&& bin_unpack_u64(bu, &event->file_size)
|
||||
&& bin_unpack_bin(bu, &event->filename, &event->filename_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv *tox_events_add_file_recv(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_size == events->file_recv_capacity) {
|
||||
const uint32_t new_file_recv_capacity = events->file_recv_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv *new_file_recv = (Tox_Event_File_Recv *)realloc(
|
||||
events->file_recv, new_file_recv_capacity * sizeof(Tox_Event_File_Recv));
|
||||
|
||||
if (new_file_recv == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv = new_file_recv;
|
||||
events->file_recv_capacity = new_file_recv_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv *const file_recv = &events->file_recv[events->file_recv_size];
|
||||
tox_event_file_recv_construct(file_recv);
|
||||
++events->file_recv_size;
|
||||
return file_recv;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_size; ++i) {
|
||||
tox_event_file_recv_destruct(&events->file_recv[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv);
|
||||
events->file_recv = nullptr;
|
||||
events->file_recv_size = 0;
|
||||
events->file_recv_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv *tox_events_get_file_recv(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_size);
|
||||
assert(events->file_recv != nullptr);
|
||||
return &events->file_recv[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_pack(tox_events_get_file_recv(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv *event = tox_events_add_file_recv(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind,
|
||||
uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv *file_recv = tox_events_add_file_recv(state->events);
|
||||
|
||||
if (file_recv == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_set_friend_number(file_recv, friend_number);
|
||||
tox_event_file_recv_set_file_number(file_recv, file_number);
|
||||
tox_event_file_recv_set_kind(file_recv, kind);
|
||||
tox_event_file_recv_set_file_size(file_recv, file_size);
|
||||
tox_event_file_recv_set_filename(file_recv, filename, filename_length);
|
||||
}
|
265
external/toxcore/c-toxcore/toxcore/events/file_recv_chunk.c
vendored
Normal file
265
external/toxcore/c-toxcore/toxcore/events/file_recv_chunk.c
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv_Chunk {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint64_t position;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_construct(Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
*file_recv_chunk = (Tox_Event_File_Recv_Chunk) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_destruct(Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
free(file_recv_chunk->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_friend_number(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_friend_number(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_file_number(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_file_number(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_position(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint64_t position)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->position = position;
|
||||
}
|
||||
uint64_t tox_event_file_recv_chunk_get_position(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->position;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_set_data(Tox_Event_File_Recv_Chunk *file_recv_chunk, const uint8_t *data,
|
||||
uint32_t data_length)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
|
||||
if (file_recv_chunk->data != nullptr) {
|
||||
free(file_recv_chunk->data);
|
||||
file_recv_chunk->data = nullptr;
|
||||
file_recv_chunk->data_length = 0;
|
||||
}
|
||||
|
||||
file_recv_chunk->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (file_recv_chunk->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(file_recv_chunk->data, data, data_length);
|
||||
file_recv_chunk->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_length(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_file_recv_chunk_get_data(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_pack(
|
||||
const Tox_Event_File_Recv_Chunk *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV_CHUNK)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u64(bp, event->position)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_unpack(
|
||||
Tox_Event_File_Recv_Chunk *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u64(bu, &event->position)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv_Chunk *tox_events_add_file_recv_chunk(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_chunk_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_chunk_size == events->file_recv_chunk_capacity) {
|
||||
const uint32_t new_file_recv_chunk_capacity = events->file_recv_chunk_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv_Chunk *new_file_recv_chunk = (Tox_Event_File_Recv_Chunk *)realloc(
|
||||
events->file_recv_chunk, new_file_recv_chunk_capacity * sizeof(Tox_Event_File_Recv_Chunk));
|
||||
|
||||
if (new_file_recv_chunk == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv_chunk = new_file_recv_chunk;
|
||||
events->file_recv_chunk_capacity = new_file_recv_chunk_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Chunk *const file_recv_chunk = &events->file_recv_chunk[events->file_recv_chunk_size];
|
||||
tox_event_file_recv_chunk_construct(file_recv_chunk);
|
||||
++events->file_recv_chunk_size;
|
||||
return file_recv_chunk;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv_chunk(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_chunk_size; ++i) {
|
||||
tox_event_file_recv_chunk_destruct(&events->file_recv_chunk[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv_chunk);
|
||||
events->file_recv_chunk = nullptr;
|
||||
events->file_recv_chunk_size = 0;
|
||||
events->file_recv_chunk_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_chunk_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_chunk_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv_Chunk *tox_events_get_file_recv_chunk(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_chunk_size);
|
||||
assert(events->file_recv_chunk != nullptr);
|
||||
return &events->file_recv_chunk[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv_chunk(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_chunk_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_chunk_pack(tox_events_get_file_recv_chunk(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv_chunk(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv_Chunk *event = tox_events_add_file_recv_chunk(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_chunk_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Chunk *file_recv_chunk = tox_events_add_file_recv_chunk(state->events);
|
||||
|
||||
if (file_recv_chunk == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_chunk_set_friend_number(file_recv_chunk, friend_number);
|
||||
tox_event_file_recv_chunk_set_file_number(file_recv_chunk, file_number);
|
||||
tox_event_file_recv_chunk_set_position(file_recv_chunk, position);
|
||||
tox_event_file_recv_chunk_set_data(file_recv_chunk, data, length);
|
||||
}
|
228
external/toxcore/c-toxcore/toxcore/events/file_recv_control.c
vendored
Normal file
228
external/toxcore/c-toxcore/toxcore/events/file_recv_control.c
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv_Control {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
Tox_File_Control control;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_construct(Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
*file_recv_control = (Tox_Event_File_Recv_Control) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_destruct(Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_friend_number(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_control_get_friend_number(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_file_number(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_control_get_file_number(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_control(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
Tox_File_Control control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->control = control;
|
||||
}
|
||||
Tox_File_Control tox_event_file_recv_control_get_control(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->control;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_control_pack(
|
||||
const Tox_Event_File_Recv_Control *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV_CONTROL)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u32(bp, event->control);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_control_unpack(
|
||||
Tox_Event_File_Recv_Control *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& tox_unpack_file_control(bu, &event->control);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv_Control *tox_events_add_file_recv_control(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_control_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_control_size == events->file_recv_control_capacity) {
|
||||
const uint32_t new_file_recv_control_capacity = events->file_recv_control_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv_Control *new_file_recv_control = (Tox_Event_File_Recv_Control *)realloc(
|
||||
events->file_recv_control, new_file_recv_control_capacity * sizeof(Tox_Event_File_Recv_Control));
|
||||
|
||||
if (new_file_recv_control == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv_control = new_file_recv_control;
|
||||
events->file_recv_control_capacity = new_file_recv_control_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Control *const file_recv_control = &events->file_recv_control[events->file_recv_control_size];
|
||||
tox_event_file_recv_control_construct(file_recv_control);
|
||||
++events->file_recv_control_size;
|
||||
return file_recv_control;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv_control(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_control_size; ++i) {
|
||||
tox_event_file_recv_control_destruct(&events->file_recv_control[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv_control);
|
||||
events->file_recv_control = nullptr;
|
||||
events->file_recv_control_size = 0;
|
||||
events->file_recv_control_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_control_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_control_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv_Control *tox_events_get_file_recv_control(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_control_size);
|
||||
assert(events->file_recv_control != nullptr);
|
||||
return &events->file_recv_control[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv_control(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_control_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_control_pack(tox_events_get_file_recv_control(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv_control(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv_Control *event = tox_events_add_file_recv_control(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_control_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv_control(Tox *tox, uint32_t friend_number, uint32_t file_number,
|
||||
Tox_File_Control control, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Control *file_recv_control = tox_events_add_file_recv_control(state->events);
|
||||
|
||||
if (file_recv_control == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_control_set_friend_number(file_recv_control, friend_number);
|
||||
tox_event_file_recv_control_set_file_number(file_recv_control, file_number);
|
||||
tox_event_file_recv_control_set_control(file_recv_control, control);
|
||||
}
|
215
external/toxcore/c-toxcore/toxcore/events/friend_connection_status.c
vendored
Normal file
215
external/toxcore/c-toxcore/toxcore/events/friend_connection_status.c
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Connection_Status {
|
||||
uint32_t friend_number;
|
||||
Tox_Connection connection_status;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_construct(Tox_Event_Friend_Connection_Status *friend_connection_status)
|
||||
{
|
||||
*friend_connection_status = (Tox_Event_Friend_Connection_Status) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_destruct(Tox_Event_Friend_Connection_Status *friend_connection_status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_set_friend_number(Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status, uint32_t friend_number)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
friend_connection_status->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_connection_status_get_friend_number(const Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
return friend_connection_status->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_set_connection_status(Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status, Tox_Connection connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
friend_connection_status->connection_status = connection_status;
|
||||
}
|
||||
Tox_Connection tox_event_friend_connection_status_get_connection_status(const Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
return friend_connection_status->connection_status;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_connection_status_pack(
|
||||
const Tox_Event_Friend_Connection_Status *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_CONNECTION_STATUS)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->connection_status);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_connection_status_unpack(
|
||||
Tox_Event_Friend_Connection_Status *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_connection(bu, &event->connection_status);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Connection_Status *tox_events_add_friend_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_connection_status_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_connection_status_size == events->friend_connection_status_capacity) {
|
||||
const uint32_t new_friend_connection_status_capacity = events->friend_connection_status_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Connection_Status *new_friend_connection_status = (Tox_Event_Friend_Connection_Status *)realloc(
|
||||
events->friend_connection_status, new_friend_connection_status_capacity * sizeof(Tox_Event_Friend_Connection_Status));
|
||||
|
||||
if (new_friend_connection_status == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_connection_status = new_friend_connection_status;
|
||||
events->friend_connection_status_capacity = new_friend_connection_status_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Connection_Status *const friend_connection_status =
|
||||
&events->friend_connection_status[events->friend_connection_status_size];
|
||||
tox_event_friend_connection_status_construct(friend_connection_status);
|
||||
++events->friend_connection_status_size;
|
||||
return friend_connection_status;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_connection_status_size; ++i) {
|
||||
tox_event_friend_connection_status_destruct(&events->friend_connection_status[i]);
|
||||
}
|
||||
|
||||
free(events->friend_connection_status);
|
||||
events->friend_connection_status = nullptr;
|
||||
events->friend_connection_status_size = 0;
|
||||
events->friend_connection_status_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_connection_status_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_connection_status_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Connection_Status *tox_events_get_friend_connection_status(const Tox_Events *events,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_connection_status_size);
|
||||
assert(events->friend_connection_status != nullptr);
|
||||
return &events->friend_connection_status[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_connection_status(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_connection_status_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_connection_status_pack(tox_events_get_friend_connection_status(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_connection_status(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Connection_Status *event = tox_events_add_friend_connection_status(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_connection_status_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_connection_status(Tox *tox, uint32_t friend_number, Tox_Connection connection_status,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Connection_Status *friend_connection_status = tox_events_add_friend_connection_status(state->events);
|
||||
|
||||
if (friend_connection_status == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_connection_status_set_friend_number(friend_connection_status, friend_number);
|
||||
tox_event_friend_connection_status_set_connection_status(friend_connection_status, connection_status);
|
||||
}
|
233
external/toxcore/c-toxcore/toxcore/events/friend_lossless_packet.c
vendored
Normal file
233
external/toxcore/c-toxcore/toxcore/events/friend_lossless_packet.c
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Lossless_Packet {
|
||||
uint32_t friend_number;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_construct(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
*friend_lossless_packet = (Tox_Event_Friend_Lossless_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_destruct(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
free(friend_lossless_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_set_friend_number(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
friend_lossless_packet->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_lossless_packet_get_friend_number(const Tox_Event_Friend_Lossless_Packet
|
||||
*friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_set_data(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
|
||||
if (friend_lossless_packet->data != nullptr) {
|
||||
free(friend_lossless_packet->data);
|
||||
friend_lossless_packet->data = nullptr;
|
||||
friend_lossless_packet->data_length = 0;
|
||||
}
|
||||
|
||||
friend_lossless_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (friend_lossless_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_lossless_packet->data, data, data_length);
|
||||
friend_lossless_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_lossless_packet_get_data_length(const Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_lossless_packet_get_data(const Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_pack(
|
||||
const Tox_Event_Friend_Lossless_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_LOSSLESS_PACKET)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_unpack(
|
||||
Tox_Event_Friend_Lossless_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Lossless_Packet *tox_events_add_friend_lossless_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_lossless_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_lossless_packet_size == events->friend_lossless_packet_capacity) {
|
||||
const uint32_t new_friend_lossless_packet_capacity = events->friend_lossless_packet_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Lossless_Packet *new_friend_lossless_packet = (Tox_Event_Friend_Lossless_Packet *)realloc(
|
||||
events->friend_lossless_packet, new_friend_lossless_packet_capacity * sizeof(Tox_Event_Friend_Lossless_Packet));
|
||||
|
||||
if (new_friend_lossless_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_lossless_packet = new_friend_lossless_packet;
|
||||
events->friend_lossless_packet_capacity = new_friend_lossless_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *const friend_lossless_packet =
|
||||
&events->friend_lossless_packet[events->friend_lossless_packet_size];
|
||||
tox_event_friend_lossless_packet_construct(friend_lossless_packet);
|
||||
++events->friend_lossless_packet_size;
|
||||
return friend_lossless_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_lossless_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_lossless_packet_size; ++i) {
|
||||
tox_event_friend_lossless_packet_destruct(&events->friend_lossless_packet[i]);
|
||||
}
|
||||
|
||||
free(events->friend_lossless_packet);
|
||||
events->friend_lossless_packet = nullptr;
|
||||
events->friend_lossless_packet_size = 0;
|
||||
events->friend_lossless_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_lossless_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_lossless_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Lossless_Packet *tox_events_get_friend_lossless_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_lossless_packet_size);
|
||||
assert(events->friend_lossless_packet != nullptr);
|
||||
return &events->friend_lossless_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_lossless_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_lossless_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_lossless_packet_pack(tox_events_get_friend_lossless_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_lossless_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Lossless_Packet *event = tox_events_add_friend_lossless_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_lossless_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet = tox_events_add_friend_lossless_packet(state->events);
|
||||
|
||||
if (friend_lossless_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_lossless_packet_set_friend_number(friend_lossless_packet, friend_number);
|
||||
tox_event_friend_lossless_packet_set_data(friend_lossless_packet, data, length);
|
||||
}
|
232
external/toxcore/c-toxcore/toxcore/events/friend_lossy_packet.c
vendored
Normal file
232
external/toxcore/c-toxcore/toxcore/events/friend_lossy_packet.c
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Lossy_Packet {
|
||||
uint32_t friend_number;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_construct(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
*friend_lossy_packet = (Tox_Event_Friend_Lossy_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_destruct(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
free(friend_lossy_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_set_friend_number(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
friend_lossy_packet->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_lossy_packet_get_friend_number(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_set_data(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
|
||||
if (friend_lossy_packet->data != nullptr) {
|
||||
free(friend_lossy_packet->data);
|
||||
friend_lossy_packet->data = nullptr;
|
||||
friend_lossy_packet->data_length = 0;
|
||||
}
|
||||
|
||||
friend_lossy_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (friend_lossy_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_lossy_packet->data, data, data_length);
|
||||
friend_lossy_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_lossy_packet_get_data_length(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_lossy_packet_get_data(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_pack(
|
||||
const Tox_Event_Friend_Lossy_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_LOSSY_PACKET)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_unpack(
|
||||
Tox_Event_Friend_Lossy_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Lossy_Packet *tox_events_add_friend_lossy_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_lossy_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_lossy_packet_size == events->friend_lossy_packet_capacity) {
|
||||
const uint32_t new_friend_lossy_packet_capacity = events->friend_lossy_packet_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Lossy_Packet *new_friend_lossy_packet = (Tox_Event_Friend_Lossy_Packet *)realloc(
|
||||
events->friend_lossy_packet, new_friend_lossy_packet_capacity * sizeof(Tox_Event_Friend_Lossy_Packet));
|
||||
|
||||
if (new_friend_lossy_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_lossy_packet = new_friend_lossy_packet;
|
||||
events->friend_lossy_packet_capacity = new_friend_lossy_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *const friend_lossy_packet =
|
||||
&events->friend_lossy_packet[events->friend_lossy_packet_size];
|
||||
tox_event_friend_lossy_packet_construct(friend_lossy_packet);
|
||||
++events->friend_lossy_packet_size;
|
||||
return friend_lossy_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_lossy_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_lossy_packet_size; ++i) {
|
||||
tox_event_friend_lossy_packet_destruct(&events->friend_lossy_packet[i]);
|
||||
}
|
||||
|
||||
free(events->friend_lossy_packet);
|
||||
events->friend_lossy_packet = nullptr;
|
||||
events->friend_lossy_packet_size = 0;
|
||||
events->friend_lossy_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_lossy_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_lossy_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Lossy_Packet *tox_events_get_friend_lossy_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_lossy_packet_size);
|
||||
assert(events->friend_lossy_packet != nullptr);
|
||||
return &events->friend_lossy_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_lossy_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_lossy_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_lossy_packet_pack(tox_events_get_friend_lossy_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_lossy_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Lossy_Packet *event = tox_events_add_friend_lossy_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_lossy_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet = tox_events_add_friend_lossy_packet(state->events);
|
||||
|
||||
if (friend_lossy_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_lossy_packet_set_friend_number(friend_lossy_packet, friend_number);
|
||||
tox_event_friend_lossy_packet_set_data(friend_lossy_packet, data, length);
|
||||
}
|
248
external/toxcore/c-toxcore/toxcore/events/friend_message.c
vendored
Normal file
248
external/toxcore/c-toxcore/toxcore/events/friend_message.c
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Message {
|
||||
uint32_t friend_number;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_construct(Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
*friend_message = (Tox_Event_Friend_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_message_destruct(Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
free(friend_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_set_friend_number(Tox_Event_Friend_Message *friend_message,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
friend_message->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_message_get_friend_number(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_set_type(Tox_Event_Friend_Message *friend_message, Tox_Message_Type type)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
friend_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_friend_message_get_type(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_set_message(Tox_Event_Friend_Message *friend_message, const uint8_t *message,
|
||||
uint32_t message_length)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
|
||||
if (friend_message->message != nullptr) {
|
||||
free(friend_message->message);
|
||||
friend_message->message = nullptr;
|
||||
friend_message->message_length = 0;
|
||||
}
|
||||
|
||||
friend_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (friend_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_message->message, message, message_length);
|
||||
friend_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_message_get_message_length(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_message_get_message(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_pack(
|
||||
const Tox_Event_Friend_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_MESSAGE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_unpack(
|
||||
Tox_Event_Friend_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Message *tox_events_add_friend_message(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_message_size == events->friend_message_capacity) {
|
||||
const uint32_t new_friend_message_capacity = events->friend_message_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Message *new_friend_message = (Tox_Event_Friend_Message *)realloc(
|
||||
events->friend_message, new_friend_message_capacity * sizeof(Tox_Event_Friend_Message));
|
||||
|
||||
if (new_friend_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_message = new_friend_message;
|
||||
events->friend_message_capacity = new_friend_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Message *const friend_message = &events->friend_message[events->friend_message_size];
|
||||
tox_event_friend_message_construct(friend_message);
|
||||
++events->friend_message_size;
|
||||
return friend_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_message_size; ++i) {
|
||||
tox_event_friend_message_destruct(&events->friend_message[i]);
|
||||
}
|
||||
|
||||
free(events->friend_message);
|
||||
events->friend_message = nullptr;
|
||||
events->friend_message_size = 0;
|
||||
events->friend_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Message *tox_events_get_friend_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_message_size);
|
||||
assert(events->friend_message != nullptr);
|
||||
return &events->friend_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_message_pack(tox_events_get_friend_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Message *event = tox_events_add_friend_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Message *friend_message = tox_events_add_friend_message(state->events);
|
||||
|
||||
if (friend_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_message_set_friend_number(friend_message, friend_number);
|
||||
tox_event_friend_message_set_type(friend_message, type);
|
||||
tox_event_friend_message_set_message(friend_message, message, length);
|
||||
}
|
231
external/toxcore/c-toxcore/toxcore/events/friend_name.c
vendored
Normal file
231
external/toxcore/c-toxcore/toxcore/events/friend_name.c
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Name {
|
||||
uint32_t friend_number;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_name_construct(Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
*friend_name = (Tox_Event_Friend_Name) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_name_destruct(Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
free(friend_name->name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_name_set_friend_number(Tox_Event_Friend_Name *friend_name,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
friend_name->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_name_get_friend_number(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_set_name(Tox_Event_Friend_Name *friend_name, const uint8_t *name,
|
||||
uint32_t name_length)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
|
||||
if (friend_name->name != nullptr) {
|
||||
free(friend_name->name);
|
||||
friend_name->name = nullptr;
|
||||
friend_name->name_length = 0;
|
||||
}
|
||||
|
||||
friend_name->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (friend_name->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_name->name, name, name_length);
|
||||
friend_name->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_name_get_name_length(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_name_get_name(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_pack(
|
||||
const Tox_Event_Friend_Name *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_NAME)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_unpack(
|
||||
Tox_Event_Friend_Name *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Name *tox_events_add_friend_name(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_name_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_name_size == events->friend_name_capacity) {
|
||||
const uint32_t new_friend_name_capacity = events->friend_name_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Name *new_friend_name = (Tox_Event_Friend_Name *)realloc(
|
||||
events->friend_name, new_friend_name_capacity * sizeof(Tox_Event_Friend_Name));
|
||||
|
||||
if (new_friend_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_name = new_friend_name;
|
||||
events->friend_name_capacity = new_friend_name_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Name *const friend_name = &events->friend_name[events->friend_name_size];
|
||||
tox_event_friend_name_construct(friend_name);
|
||||
++events->friend_name_size;
|
||||
return friend_name;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_name(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_name_size; ++i) {
|
||||
tox_event_friend_name_destruct(&events->friend_name[i]);
|
||||
}
|
||||
|
||||
free(events->friend_name);
|
||||
events->friend_name = nullptr;
|
||||
events->friend_name_size = 0;
|
||||
events->friend_name_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_name_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_name_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Name *tox_events_get_friend_name(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_name_size);
|
||||
assert(events->friend_name != nullptr);
|
||||
return &events->friend_name[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_name(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_name_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_name_pack(tox_events_get_friend_name(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_name(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Name *event = tox_events_add_friend_name(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_name_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_name(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Name *friend_name = tox_events_add_friend_name(state->events);
|
||||
|
||||
if (friend_name == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_name_set_friend_number(friend_name, friend_number);
|
||||
tox_event_friend_name_set_name(friend_name, name, length);
|
||||
}
|
210
external/toxcore/c-toxcore/toxcore/events/friend_read_receipt.c
vendored
Normal file
210
external/toxcore/c-toxcore/toxcore/events/friend_read_receipt.c
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Read_Receipt {
|
||||
uint32_t friend_number;
|
||||
uint32_t message_id;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_read_receipt_construct(Tox_Event_Friend_Read_Receipt *friend_read_receipt)
|
||||
{
|
||||
*friend_read_receipt = (Tox_Event_Friend_Read_Receipt) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_read_receipt_destruct(Tox_Event_Friend_Read_Receipt *friend_read_receipt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_read_receipt_set_friend_number(Tox_Event_Friend_Read_Receipt *friend_read_receipt,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_read_receipt != nullptr);
|
||||
friend_read_receipt->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_read_receipt_get_friend_number(const Tox_Event_Friend_Read_Receipt *friend_read_receipt)
|
||||
{
|
||||
assert(friend_read_receipt != nullptr);
|
||||
return friend_read_receipt->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_read_receipt_set_message_id(Tox_Event_Friend_Read_Receipt *friend_read_receipt,
|
||||
uint32_t message_id)
|
||||
{
|
||||
assert(friend_read_receipt != nullptr);
|
||||
friend_read_receipt->message_id = message_id;
|
||||
}
|
||||
uint32_t tox_event_friend_read_receipt_get_message_id(const Tox_Event_Friend_Read_Receipt *friend_read_receipt)
|
||||
{
|
||||
assert(friend_read_receipt != nullptr);
|
||||
return friend_read_receipt->message_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_read_receipt_pack(
|
||||
const Tox_Event_Friend_Read_Receipt *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_READ_RECEIPT)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->message_id);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_read_receipt_unpack(
|
||||
Tox_Event_Friend_Read_Receipt *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->message_id);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Read_Receipt *tox_events_add_friend_read_receipt(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_read_receipt_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_read_receipt_size == events->friend_read_receipt_capacity) {
|
||||
const uint32_t new_friend_read_receipt_capacity = events->friend_read_receipt_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Read_Receipt *new_friend_read_receipt = (Tox_Event_Friend_Read_Receipt *)realloc(
|
||||
events->friend_read_receipt, new_friend_read_receipt_capacity * sizeof(Tox_Event_Friend_Read_Receipt));
|
||||
|
||||
if (new_friend_read_receipt == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_read_receipt = new_friend_read_receipt;
|
||||
events->friend_read_receipt_capacity = new_friend_read_receipt_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Read_Receipt *const friend_read_receipt =
|
||||
&events->friend_read_receipt[events->friend_read_receipt_size];
|
||||
tox_event_friend_read_receipt_construct(friend_read_receipt);
|
||||
++events->friend_read_receipt_size;
|
||||
return friend_read_receipt;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_read_receipt(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_read_receipt_size; ++i) {
|
||||
tox_event_friend_read_receipt_destruct(&events->friend_read_receipt[i]);
|
||||
}
|
||||
|
||||
free(events->friend_read_receipt);
|
||||
events->friend_read_receipt = nullptr;
|
||||
events->friend_read_receipt_size = 0;
|
||||
events->friend_read_receipt_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_read_receipt_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_read_receipt_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Read_Receipt *tox_events_get_friend_read_receipt(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_read_receipt_size);
|
||||
assert(events->friend_read_receipt != nullptr);
|
||||
return &events->friend_read_receipt[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_read_receipt(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_read_receipt_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_read_receipt_pack(tox_events_get_friend_read_receipt(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_read_receipt(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Read_Receipt *event = tox_events_add_friend_read_receipt(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_read_receipt_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_read_receipt(Tox *tox, uint32_t friend_number, uint32_t message_id, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Read_Receipt *friend_read_receipt = tox_events_add_friend_read_receipt(state->events);
|
||||
|
||||
if (friend_read_receipt == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_read_receipt_set_friend_number(friend_read_receipt, friend_number);
|
||||
tox_event_friend_read_receipt_set_message_id(friend_read_receipt, message_id);
|
||||
}
|
232
external/toxcore/c-toxcore/toxcore/events/friend_request.c
vendored
Normal file
232
external/toxcore/c-toxcore/toxcore/events/friend_request.c
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Request {
|
||||
uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_request_construct(Tox_Event_Friend_Request *friend_request)
|
||||
{
|
||||
*friend_request = (Tox_Event_Friend_Request) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_request_destruct(Tox_Event_Friend_Request *friend_request)
|
||||
{
|
||||
free(friend_request->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_request_set_public_key(Tox_Event_Friend_Request *friend_request, const uint8_t *public_key)
|
||||
{
|
||||
assert(friend_request != nullptr);
|
||||
|
||||
memcpy(friend_request->public_key, public_key, TOX_PUBLIC_KEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
const uint8_t *tox_event_friend_request_get_public_key(const Tox_Event_Friend_Request *friend_request)
|
||||
{
|
||||
assert(friend_request != nullptr);
|
||||
return friend_request->public_key;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_request_set_message(Tox_Event_Friend_Request *friend_request, const uint8_t *message,
|
||||
uint32_t message_length)
|
||||
{
|
||||
assert(friend_request != nullptr);
|
||||
|
||||
if (friend_request->message != nullptr) {
|
||||
free(friend_request->message);
|
||||
friend_request->message = nullptr;
|
||||
friend_request->message_length = 0;
|
||||
}
|
||||
|
||||
friend_request->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (friend_request->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_request->message, message, message_length);
|
||||
friend_request->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_request_get_message_length(const Tox_Event_Friend_Request *friend_request)
|
||||
{
|
||||
assert(friend_request != nullptr);
|
||||
return friend_request->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_request_get_message(const Tox_Event_Friend_Request *friend_request)
|
||||
{
|
||||
assert(friend_request != nullptr);
|
||||
return friend_request->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_request_pack(
|
||||
const Tox_Event_Friend_Request *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_REQUEST)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_bin(bp, event->public_key, TOX_PUBLIC_KEY_SIZE)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_request_unpack(
|
||||
Tox_Event_Friend_Request *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_bin_fixed(bu, event->public_key, TOX_PUBLIC_KEY_SIZE)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Request *tox_events_add_friend_request(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_request_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_request_size == events->friend_request_capacity) {
|
||||
const uint32_t new_friend_request_capacity = events->friend_request_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Request *new_friend_request = (Tox_Event_Friend_Request *)realloc(
|
||||
events->friend_request, new_friend_request_capacity * sizeof(Tox_Event_Friend_Request));
|
||||
|
||||
if (new_friend_request == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_request = new_friend_request;
|
||||
events->friend_request_capacity = new_friend_request_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Request *const friend_request = &events->friend_request[events->friend_request_size];
|
||||
tox_event_friend_request_construct(friend_request);
|
||||
++events->friend_request_size;
|
||||
return friend_request;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_request(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_request_size; ++i) {
|
||||
tox_event_friend_request_destruct(&events->friend_request[i]);
|
||||
}
|
||||
|
||||
free(events->friend_request);
|
||||
events->friend_request = nullptr;
|
||||
events->friend_request_size = 0;
|
||||
events->friend_request_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_request_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_request_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Request *tox_events_get_friend_request(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_request_size);
|
||||
assert(events->friend_request != nullptr);
|
||||
return &events->friend_request[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_request(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_request_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_request_pack(tox_events_get_friend_request(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_request(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Request *event = tox_events_add_friend_request(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_request_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Request *friend_request = tox_events_add_friend_request(state->events);
|
||||
|
||||
if (friend_request == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_request_set_public_key(friend_request, public_key);
|
||||
tox_event_friend_request_set_message(friend_request, message, length);
|
||||
}
|
211
external/toxcore/c-toxcore/toxcore/events/friend_status.c
vendored
Normal file
211
external/toxcore/c-toxcore/toxcore/events/friend_status.c
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Status {
|
||||
uint32_t friend_number;
|
||||
Tox_User_Status status;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_status_construct(Tox_Event_Friend_Status *friend_status)
|
||||
{
|
||||
*friend_status = (Tox_Event_Friend_Status) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_status_destruct(Tox_Event_Friend_Status *friend_status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_status_set_friend_number(Tox_Event_Friend_Status *friend_status,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_status != nullptr);
|
||||
friend_status->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_status_get_friend_number(const Tox_Event_Friend_Status *friend_status)
|
||||
{
|
||||
assert(friend_status != nullptr);
|
||||
return friend_status->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_status_set_status(Tox_Event_Friend_Status *friend_status,
|
||||
Tox_User_Status status)
|
||||
{
|
||||
assert(friend_status != nullptr);
|
||||
friend_status->status = status;
|
||||
}
|
||||
Tox_User_Status tox_event_friend_status_get_status(const Tox_Event_Friend_Status *friend_status)
|
||||
{
|
||||
assert(friend_status != nullptr);
|
||||
return friend_status->status;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_status_pack(
|
||||
const Tox_Event_Friend_Status *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_STATUS)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->status);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_status_unpack(
|
||||
Tox_Event_Friend_Status *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_user_status(bu, &event->status);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Status *tox_events_add_friend_status(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_status_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_status_size == events->friend_status_capacity) {
|
||||
const uint32_t new_friend_status_capacity = events->friend_status_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Status *new_friend_status = (Tox_Event_Friend_Status *)realloc(
|
||||
events->friend_status, new_friend_status_capacity * sizeof(Tox_Event_Friend_Status));
|
||||
|
||||
if (new_friend_status == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_status = new_friend_status;
|
||||
events->friend_status_capacity = new_friend_status_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Status *const friend_status = &events->friend_status[events->friend_status_size];
|
||||
tox_event_friend_status_construct(friend_status);
|
||||
++events->friend_status_size;
|
||||
return friend_status;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_status(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_status_size; ++i) {
|
||||
tox_event_friend_status_destruct(&events->friend_status[i]);
|
||||
}
|
||||
|
||||
free(events->friend_status);
|
||||
events->friend_status = nullptr;
|
||||
events->friend_status_size = 0;
|
||||
events->friend_status_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_status_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_status_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Status *tox_events_get_friend_status(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_status_size);
|
||||
assert(events->friend_status != nullptr);
|
||||
return &events->friend_status[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_status(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_status_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_status_pack(tox_events_get_friend_status(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_status(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Status *event = tox_events_add_friend_status(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_status_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_status(Tox *tox, uint32_t friend_number, Tox_User_Status status,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Status *friend_status = tox_events_add_friend_status(state->events);
|
||||
|
||||
if (friend_status == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_status_set_friend_number(friend_status, friend_number);
|
||||
tox_event_friend_status_set_status(friend_status, status);
|
||||
}
|
234
external/toxcore/c-toxcore/toxcore/events/friend_status_message.c
vendored
Normal file
234
external/toxcore/c-toxcore/toxcore/events/friend_status_message.c
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Status_Message {
|
||||
uint32_t friend_number;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_status_message_construct(Tox_Event_Friend_Status_Message *friend_status_message)
|
||||
{
|
||||
*friend_status_message = (Tox_Event_Friend_Status_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_status_message_destruct(Tox_Event_Friend_Status_Message *friend_status_message)
|
||||
{
|
||||
free(friend_status_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_status_message_set_friend_number(Tox_Event_Friend_Status_Message *friend_status_message,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_status_message != nullptr);
|
||||
friend_status_message->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_status_message_get_friend_number(const Tox_Event_Friend_Status_Message *friend_status_message)
|
||||
{
|
||||
assert(friend_status_message != nullptr);
|
||||
return friend_status_message->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_status_message_set_message(Tox_Event_Friend_Status_Message *friend_status_message,
|
||||
const uint8_t *message, uint32_t message_length)
|
||||
{
|
||||
assert(friend_status_message != nullptr);
|
||||
|
||||
if (friend_status_message->message != nullptr) {
|
||||
free(friend_status_message->message);
|
||||
friend_status_message->message = nullptr;
|
||||
friend_status_message->message_length = 0;
|
||||
}
|
||||
|
||||
friend_status_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (friend_status_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_status_message->message, message, message_length);
|
||||
friend_status_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_status_message_get_message_length(const Tox_Event_Friend_Status_Message
|
||||
*friend_status_message)
|
||||
{
|
||||
assert(friend_status_message != nullptr);
|
||||
return friend_status_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_status_message_get_message(const Tox_Event_Friend_Status_Message
|
||||
*friend_status_message)
|
||||
{
|
||||
assert(friend_status_message != nullptr);
|
||||
return friend_status_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_status_message_pack(
|
||||
const Tox_Event_Friend_Status_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_STATUS_MESSAGE)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_status_message_unpack(
|
||||
Tox_Event_Friend_Status_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Status_Message *tox_events_add_friend_status_message(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_status_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_status_message_size == events->friend_status_message_capacity) {
|
||||
const uint32_t new_friend_status_message_capacity = events->friend_status_message_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Status_Message *new_friend_status_message = (Tox_Event_Friend_Status_Message *)realloc(
|
||||
events->friend_status_message, new_friend_status_message_capacity * sizeof(Tox_Event_Friend_Status_Message));
|
||||
|
||||
if (new_friend_status_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_status_message = new_friend_status_message;
|
||||
events->friend_status_message_capacity = new_friend_status_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Status_Message *const friend_status_message =
|
||||
&events->friend_status_message[events->friend_status_message_size];
|
||||
tox_event_friend_status_message_construct(friend_status_message);
|
||||
++events->friend_status_message_size;
|
||||
return friend_status_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_status_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_status_message_size; ++i) {
|
||||
tox_event_friend_status_message_destruct(&events->friend_status_message[i]);
|
||||
}
|
||||
|
||||
free(events->friend_status_message);
|
||||
events->friend_status_message = nullptr;
|
||||
events->friend_status_message_size = 0;
|
||||
events->friend_status_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_status_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_status_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Status_Message *tox_events_get_friend_status_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_status_message_size);
|
||||
assert(events->friend_status_message != nullptr);
|
||||
return &events->friend_status_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_status_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_status_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_status_message_pack(tox_events_get_friend_status_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_status_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Status_Message *event = tox_events_add_friend_status_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_status_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_status_message(Tox *tox, uint32_t friend_number, const uint8_t *message,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Status_Message *friend_status_message = tox_events_add_friend_status_message(state->events);
|
||||
|
||||
if (friend_status_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_status_message_set_friend_number(friend_status_message, friend_number);
|
||||
tox_event_friend_status_message_set_message(friend_status_message, message, length);
|
||||
}
|
208
external/toxcore/c-toxcore/toxcore/events/friend_typing.c
vendored
Normal file
208
external/toxcore/c-toxcore/toxcore/events/friend_typing.c
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Typing {
|
||||
uint32_t friend_number;
|
||||
bool typing;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_typing_construct(Tox_Event_Friend_Typing *friend_typing)
|
||||
{
|
||||
*friend_typing = (Tox_Event_Friend_Typing) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_typing_destruct(Tox_Event_Friend_Typing *friend_typing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_typing_set_friend_number(Tox_Event_Friend_Typing *friend_typing,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_typing != nullptr);
|
||||
friend_typing->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_typing_get_friend_number(const Tox_Event_Friend_Typing *friend_typing)
|
||||
{
|
||||
assert(friend_typing != nullptr);
|
||||
return friend_typing->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_typing_set_typing(Tox_Event_Friend_Typing *friend_typing, bool typing)
|
||||
{
|
||||
assert(friend_typing != nullptr);
|
||||
friend_typing->typing = typing;
|
||||
}
|
||||
bool tox_event_friend_typing_get_typing(const Tox_Event_Friend_Typing *friend_typing)
|
||||
{
|
||||
assert(friend_typing != nullptr);
|
||||
return friend_typing->typing;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_typing_pack(
|
||||
const Tox_Event_Friend_Typing *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_TYPING)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bool(bp, event->typing);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_typing_unpack(
|
||||
Tox_Event_Friend_Typing *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bool(bu, &event->typing);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Typing *tox_events_add_friend_typing(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_typing_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_typing_size == events->friend_typing_capacity) {
|
||||
const uint32_t new_friend_typing_capacity = events->friend_typing_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Typing *new_friend_typing = (Tox_Event_Friend_Typing *)realloc(
|
||||
events->friend_typing, new_friend_typing_capacity * sizeof(Tox_Event_Friend_Typing));
|
||||
|
||||
if (new_friend_typing == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_typing = new_friend_typing;
|
||||
events->friend_typing_capacity = new_friend_typing_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Typing *const friend_typing = &events->friend_typing[events->friend_typing_size];
|
||||
tox_event_friend_typing_construct(friend_typing);
|
||||
++events->friend_typing_size;
|
||||
return friend_typing;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_typing(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_typing_size; ++i) {
|
||||
tox_event_friend_typing_destruct(&events->friend_typing[i]);
|
||||
}
|
||||
|
||||
free(events->friend_typing);
|
||||
events->friend_typing = nullptr;
|
||||
events->friend_typing_size = 0;
|
||||
events->friend_typing_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_typing_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_typing_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Typing *tox_events_get_friend_typing(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_typing_size);
|
||||
assert(events->friend_typing != nullptr);
|
||||
return &events->friend_typing[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_typing(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_typing_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_typing_pack(tox_events_get_friend_typing(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_typing(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Typing *event = tox_events_add_friend_typing(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_typing_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_typing(Tox *tox, uint32_t friend_number, bool typing, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Typing *friend_typing = tox_events_add_friend_typing(state->events);
|
||||
|
||||
if (friend_typing == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_typing_set_friend_number(friend_typing, friend_number);
|
||||
tox_event_friend_typing_set_typing(friend_typing, typing);
|
||||
}
|
252
external/toxcore/c-toxcore/toxcore/events/group_custom_packet.c
vendored
Normal file
252
external/toxcore/c-toxcore/toxcore/events/group_custom_packet.c
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Custom_Packet {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_packet_construct(Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
*group_custom_packet = (Tox_Event_Group_Custom_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_custom_packet_destruct(Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
free(group_custom_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_packet_set_group_number(Tox_Event_Group_Custom_Packet *group_custom_packet,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
group_custom_packet->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_custom_packet_get_group_number(const Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
return group_custom_packet->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_packet_set_peer_id(Tox_Event_Group_Custom_Packet *group_custom_packet,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
group_custom_packet->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_custom_packet_get_peer_id(const Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
return group_custom_packet->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_packet_set_data(Tox_Event_Group_Custom_Packet *group_custom_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
|
||||
if (group_custom_packet->data != nullptr) {
|
||||
free(group_custom_packet->data);
|
||||
group_custom_packet->data = nullptr;
|
||||
group_custom_packet->data_length = 0;
|
||||
}
|
||||
|
||||
group_custom_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (group_custom_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_custom_packet->data, data, data_length);
|
||||
group_custom_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_custom_packet_get_data_length(const Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
return group_custom_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_custom_packet_get_data(const Tox_Event_Group_Custom_Packet *group_custom_packet)
|
||||
{
|
||||
assert(group_custom_packet != nullptr);
|
||||
return group_custom_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_packet_pack(
|
||||
const Tox_Event_Group_Custom_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_CUSTOM_PACKET)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_packet_unpack(
|
||||
Tox_Event_Group_Custom_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Custom_Packet *tox_events_add_group_custom_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->group_custom_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_custom_packet_size == events->group_custom_packet_capacity) {
|
||||
const uint32_t new_group_custom_packet_capacity = events->group_custom_packet_capacity * 2 + 1;
|
||||
Tox_Event_Group_Custom_Packet *new_group_custom_packet = (Tox_Event_Group_Custom_Packet *)
|
||||
realloc(
|
||||
events->group_custom_packet,
|
||||
new_group_custom_packet_capacity * sizeof(Tox_Event_Group_Custom_Packet));
|
||||
|
||||
if (new_group_custom_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_custom_packet = new_group_custom_packet;
|
||||
events->group_custom_packet_capacity = new_group_custom_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Custom_Packet *const group_custom_packet =
|
||||
&events->group_custom_packet[events->group_custom_packet_size];
|
||||
tox_event_group_custom_packet_construct(group_custom_packet);
|
||||
++events->group_custom_packet_size;
|
||||
return group_custom_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_custom_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_custom_packet_size; ++i) {
|
||||
tox_event_group_custom_packet_destruct(&events->group_custom_packet[i]);
|
||||
}
|
||||
|
||||
free(events->group_custom_packet);
|
||||
events->group_custom_packet = nullptr;
|
||||
events->group_custom_packet_size = 0;
|
||||
events->group_custom_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_custom_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_custom_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Custom_Packet *tox_events_get_group_custom_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_custom_packet_size);
|
||||
assert(events->group_custom_packet != nullptr);
|
||||
return &events->group_custom_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_custom_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_custom_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_custom_packet_pack(tox_events_get_group_custom_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_custom_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Custom_Packet *event = tox_events_add_group_custom_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_custom_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_custom_packet(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Custom_Packet *group_custom_packet = tox_events_add_group_custom_packet(state->events);
|
||||
|
||||
if (group_custom_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
252
external/toxcore/c-toxcore/toxcore/events/group_custom_private_packet.c
vendored
Normal file
252
external/toxcore/c-toxcore/toxcore/events/group_custom_private_packet.c
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Custom_Private_Packet {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_private_packet_construct(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
*group_custom_private_packet = (Tox_Event_Group_Custom_Private_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_custom_private_packet_destruct(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
free(group_custom_private_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_private_packet_set_group_number(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
group_custom_private_packet->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_custom_private_packet_get_group_number(const Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
return group_custom_private_packet->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_custom_private_packet_set_peer_id(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
group_custom_private_packet->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_custom_private_packet_get_peer_id(const Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
return group_custom_private_packet->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_private_packet_set_data(Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
|
||||
if (group_custom_private_packet->data != nullptr) {
|
||||
free(group_custom_private_packet->data);
|
||||
group_custom_private_packet->data = nullptr;
|
||||
group_custom_private_packet->data_length = 0;
|
||||
}
|
||||
|
||||
group_custom_private_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (group_custom_private_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_custom_private_packet->data, data, data_length);
|
||||
group_custom_private_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_custom_private_packet_get_data_length(const Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
return group_custom_private_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_custom_private_packet_get_data(const Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet)
|
||||
{
|
||||
assert(group_custom_private_packet != nullptr);
|
||||
return group_custom_private_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_private_packet_pack(
|
||||
const Tox_Event_Group_Custom_Private_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_custom_private_packet_unpack(
|
||||
Tox_Event_Group_Custom_Private_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Custom_Private_Packet *tox_events_add_group_custom_private_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->group_custom_private_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_custom_private_packet_size == events->group_custom_private_packet_capacity) {
|
||||
const uint32_t new_group_custom_private_packet_capacity = events->group_custom_private_packet_capacity * 2 + 1;
|
||||
Tox_Event_Group_Custom_Private_Packet *new_group_custom_private_packet = (Tox_Event_Group_Custom_Private_Packet *)
|
||||
realloc(
|
||||
events->group_custom_private_packet,
|
||||
new_group_custom_private_packet_capacity * sizeof(Tox_Event_Group_Custom_Private_Packet));
|
||||
|
||||
if (new_group_custom_private_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_custom_private_packet = new_group_custom_private_packet;
|
||||
events->group_custom_private_packet_capacity = new_group_custom_private_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Custom_Private_Packet *const group_custom_private_packet =
|
||||
&events->group_custom_private_packet[events->group_custom_private_packet_size];
|
||||
tox_event_group_custom_private_packet_construct(group_custom_private_packet);
|
||||
++events->group_custom_private_packet_size;
|
||||
return group_custom_private_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_custom_private_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_custom_private_packet_size; ++i) {
|
||||
tox_event_group_custom_private_packet_destruct(&events->group_custom_private_packet[i]);
|
||||
}
|
||||
|
||||
free(events->group_custom_private_packet);
|
||||
events->group_custom_private_packet = nullptr;
|
||||
events->group_custom_private_packet_size = 0;
|
||||
events->group_custom_private_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_custom_private_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_custom_private_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Custom_Private_Packet *tox_events_get_group_custom_private_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_custom_private_packet_size);
|
||||
assert(events->group_custom_private_packet != nullptr);
|
||||
return &events->group_custom_private_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_custom_private_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_custom_private_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_custom_private_packet_pack(tox_events_get_group_custom_private_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_custom_private_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Custom_Private_Packet *event = tox_events_add_group_custom_private_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_custom_private_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
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,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Custom_Private_Packet *group_custom_private_packet = tox_events_add_group_custom_private_packet(state->events);
|
||||
|
||||
if (group_custom_private_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
274
external/toxcore/c-toxcore/toxcore/events/group_invite.c
vendored
Normal file
274
external/toxcore/c-toxcore/toxcore/events/group_invite.c
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Invite {
|
||||
uint32_t friend_number;
|
||||
uint8_t *invite_data;
|
||||
uint32_t invite_data_length;
|
||||
uint8_t *group_name;
|
||||
uint32_t group_name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_invite_construct(Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
*group_invite = (Tox_Event_Group_Invite) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_invite_destruct(Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
free(group_invite->invite_data);
|
||||
free(group_invite->group_name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_invite_set_friend_number(Tox_Event_Group_Invite *group_invite,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
group_invite->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_group_invite_get_friend_number(const Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
return group_invite->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_invite_set_invite_data(Tox_Event_Group_Invite *group_invite,
|
||||
const uint8_t *invite_data, uint32_t invite_data_length)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
|
||||
if (group_invite->invite_data != nullptr) {
|
||||
free(group_invite->invite_data);
|
||||
group_invite->invite_data = nullptr;
|
||||
group_invite->invite_data_length = 0;
|
||||
}
|
||||
|
||||
group_invite->invite_data = (uint8_t *)malloc(invite_data_length);
|
||||
|
||||
if (group_invite->invite_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_invite->invite_data, invite_data, invite_data_length);
|
||||
group_invite->invite_data_length = invite_data_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_invite_get_invite_data_length(const Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
return group_invite->invite_data_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_invite_get_invite_data(const Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
return group_invite->invite_data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_invite_set_group_name(Tox_Event_Group_Invite *group_invite,
|
||||
const uint8_t *group_name, uint32_t group_name_length)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
|
||||
if (group_invite->group_name != nullptr) {
|
||||
free(group_invite->group_name);
|
||||
group_invite->group_name = nullptr;
|
||||
group_invite->group_name_length = 0;
|
||||
}
|
||||
|
||||
group_invite->group_name = (uint8_t *)malloc(group_name_length);
|
||||
|
||||
if (group_invite->group_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_invite->group_name, group_name, group_name_length);
|
||||
group_invite->group_name_length = group_name_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_invite_get_group_name_length(const Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
return group_invite->group_name_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_invite_get_group_name(const Tox_Event_Group_Invite *group_invite)
|
||||
{
|
||||
assert(group_invite != nullptr);
|
||||
return group_invite->group_name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_invite_pack(
|
||||
const Tox_Event_Group_Invite *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_INVITE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->invite_data, event->invite_data_length)
|
||||
&& bin_pack_bin(bp, event->group_name, event->group_name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_invite_unpack(
|
||||
Tox_Event_Group_Invite *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->invite_data, &event->invite_data_length)
|
||||
&& bin_unpack_bin(bu, &event->group_name, &event->group_name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Invite *tox_events_add_group_invite(Tox_Events *events)
|
||||
{
|
||||
if (events->group_invite_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_invite_size == events->group_invite_capacity) {
|
||||
const uint32_t new_group_invite_capacity = events->group_invite_capacity * 2 + 1;
|
||||
Tox_Event_Group_Invite *new_group_invite = (Tox_Event_Group_Invite *)
|
||||
realloc(
|
||||
events->group_invite,
|
||||
new_group_invite_capacity * sizeof(Tox_Event_Group_Invite));
|
||||
|
||||
if (new_group_invite == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_invite = new_group_invite;
|
||||
events->group_invite_capacity = new_group_invite_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Invite *const group_invite =
|
||||
&events->group_invite[events->group_invite_size];
|
||||
tox_event_group_invite_construct(group_invite);
|
||||
++events->group_invite_size;
|
||||
return group_invite;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_invite(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_invite_size; ++i) {
|
||||
tox_event_group_invite_destruct(&events->group_invite[i]);
|
||||
}
|
||||
|
||||
free(events->group_invite);
|
||||
events->group_invite = nullptr;
|
||||
events->group_invite_size = 0;
|
||||
events->group_invite_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_invite_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_invite_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Invite *tox_events_get_group_invite(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_invite_size);
|
||||
assert(events->group_invite != nullptr);
|
||||
return &events->group_invite[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_invite(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_invite_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_invite_pack(tox_events_get_group_invite(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_invite(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Invite *event = tox_events_add_group_invite(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_invite_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
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,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Invite *group_invite = tox_events_add_group_invite(state->events);
|
||||
|
||||
if (group_invite == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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_group_name(group_invite, group_name, group_name_length);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_join_fail.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_join_fail.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Join_Fail {
|
||||
uint32_t group_number;
|
||||
Tox_Group_Join_Fail fail_type;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_join_fail_construct(Tox_Event_Group_Join_Fail *group_join_fail)
|
||||
{
|
||||
*group_join_fail = (Tox_Event_Group_Join_Fail) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_join_fail_destruct(Tox_Event_Group_Join_Fail *group_join_fail)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_join_fail_set_group_number(Tox_Event_Group_Join_Fail *group_join_fail,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_join_fail != nullptr);
|
||||
group_join_fail->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_join_fail_get_group_number(const Tox_Event_Group_Join_Fail *group_join_fail)
|
||||
{
|
||||
assert(group_join_fail != nullptr);
|
||||
return group_join_fail->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_join_fail_set_fail_type(Tox_Event_Group_Join_Fail *group_join_fail,
|
||||
Tox_Group_Join_Fail fail_type)
|
||||
{
|
||||
assert(group_join_fail != nullptr);
|
||||
group_join_fail->fail_type = fail_type;
|
||||
}
|
||||
Tox_Group_Join_Fail tox_event_group_join_fail_get_fail_type(const Tox_Event_Group_Join_Fail *group_join_fail)
|
||||
{
|
||||
assert(group_join_fail != nullptr);
|
||||
return group_join_fail->fail_type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_join_fail_pack(
|
||||
const Tox_Event_Group_Join_Fail *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_JOIN_FAIL)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->fail_type);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_join_fail_unpack(
|
||||
Tox_Event_Group_Join_Fail *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& tox_unpack_group_join_fail(bu, &event->fail_type);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Join_Fail *tox_events_add_group_join_fail(Tox_Events *events)
|
||||
{
|
||||
if (events->group_join_fail_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_join_fail_size == events->group_join_fail_capacity) {
|
||||
const uint32_t new_group_join_fail_capacity = events->group_join_fail_capacity * 2 + 1;
|
||||
Tox_Event_Group_Join_Fail *new_group_join_fail = (Tox_Event_Group_Join_Fail *)
|
||||
realloc(
|
||||
events->group_join_fail,
|
||||
new_group_join_fail_capacity * sizeof(Tox_Event_Group_Join_Fail));
|
||||
|
||||
if (new_group_join_fail == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_join_fail = new_group_join_fail;
|
||||
events->group_join_fail_capacity = new_group_join_fail_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Join_Fail *const group_join_fail =
|
||||
&events->group_join_fail[events->group_join_fail_size];
|
||||
tox_event_group_join_fail_construct(group_join_fail);
|
||||
++events->group_join_fail_size;
|
||||
return group_join_fail;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_join_fail(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_join_fail_size; ++i) {
|
||||
tox_event_group_join_fail_destruct(&events->group_join_fail[i]);
|
||||
}
|
||||
|
||||
free(events->group_join_fail);
|
||||
events->group_join_fail = nullptr;
|
||||
events->group_join_fail_size = 0;
|
||||
events->group_join_fail_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_join_fail_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_join_fail_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Join_Fail *tox_events_get_group_join_fail(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_join_fail_size);
|
||||
assert(events->group_join_fail != nullptr);
|
||||
return &events->group_join_fail[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_join_fail(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_join_fail_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_join_fail_pack(tox_events_get_group_join_fail(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_join_fail(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Join_Fail *event = tox_events_add_group_join_fail(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_join_fail_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_join_fail(Tox *tox, uint32_t group_number, Tox_Group_Join_Fail fail_type,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Join_Fail *group_join_fail = tox_events_add_group_join_fail(state->events);
|
||||
|
||||
if (group_join_fail == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_join_fail_set_group_number(group_join_fail, group_number);
|
||||
tox_event_group_join_fail_set_fail_type(group_join_fail, fail_type);
|
||||
}
|
286
external/toxcore/c-toxcore/toxcore/events/group_message.c
vendored
Normal file
286
external/toxcore/c-toxcore/toxcore/events/group_message.c
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Message {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
uint32_t message_id;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_message_construct(Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
*group_message = (Tox_Event_Group_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_message_destruct(Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
free(group_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_message_set_group_number(Tox_Event_Group_Message *group_message,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
group_message->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_message_get_group_number(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_message_set_peer_id(Tox_Event_Group_Message *group_message,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
group_message->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_message_get_peer_id(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_message_set_type(Tox_Event_Group_Message *group_message,
|
||||
Tox_Message_Type type)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
group_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_group_message_get_type(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_message_set_message(Tox_Event_Group_Message *group_message,
|
||||
const uint8_t *message, uint32_t message_length)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
|
||||
if (group_message->message != nullptr) {
|
||||
free(group_message->message);
|
||||
group_message->message = nullptr;
|
||||
group_message->message_length = 0;
|
||||
}
|
||||
|
||||
group_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (group_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_message->message, message, message_length);
|
||||
group_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_message_get_message_length(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_message_get_message(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_message_set_message_id(Tox_Event_Group_Message *group_message,
|
||||
uint32_t message_id)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
group_message->message_id = message_id;
|
||||
}
|
||||
uint32_t tox_event_group_message_get_message_id(const Tox_Event_Group_Message *group_message)
|
||||
{
|
||||
assert(group_message != nullptr);
|
||||
return group_message->message_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_message_pack(
|
||||
const Tox_Event_Group_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_MESSAGE)
|
||||
&& bin_pack_array(bp, 5)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length)
|
||||
&& bin_pack_u32(bp, event->message_id);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_message_unpack(
|
||||
Tox_Event_Group_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length)
|
||||
&& bin_unpack_u32(bu, &event->message_id);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Message *tox_events_add_group_message(Tox_Events *events)
|
||||
{
|
||||
if (events->group_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_message_size == events->group_message_capacity) {
|
||||
const uint32_t new_group_message_capacity = events->group_message_capacity * 2 + 1;
|
||||
Tox_Event_Group_Message *new_group_message = (Tox_Event_Group_Message *)
|
||||
realloc(
|
||||
events->group_message,
|
||||
new_group_message_capacity * sizeof(Tox_Event_Group_Message));
|
||||
|
||||
if (new_group_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_message = new_group_message;
|
||||
events->group_message_capacity = new_group_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Message *const group_message =
|
||||
&events->group_message[events->group_message_size];
|
||||
tox_event_group_message_construct(group_message);
|
||||
++events->group_message_size;
|
||||
return group_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_message_size; ++i) {
|
||||
tox_event_group_message_destruct(&events->group_message[i]);
|
||||
}
|
||||
|
||||
free(events->group_message);
|
||||
events->group_message = nullptr;
|
||||
events->group_message_size = 0;
|
||||
events->group_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Message *tox_events_get_group_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_message_size);
|
||||
assert(events->group_message != nullptr);
|
||||
return &events->group_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_message_pack(tox_events_get_group_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Message *event = tox_events_add_group_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
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,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Message *group_message = tox_events_add_group_message(state->events);
|
||||
|
||||
if (group_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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_id(group_message, message_id);
|
||||
}
|
248
external/toxcore/c-toxcore/toxcore/events/group_moderation.c
vendored
Normal file
248
external/toxcore/c-toxcore/toxcore/events/group_moderation.c
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Moderation {
|
||||
uint32_t group_number;
|
||||
uint32_t source_peer_id;
|
||||
uint32_t target_peer_id;
|
||||
Tox_Group_Mod_Event mod_type;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_moderation_construct(Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
*group_moderation = (Tox_Event_Group_Moderation) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_moderation_destruct(Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_moderation_set_group_number(Tox_Event_Group_Moderation *group_moderation,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
group_moderation->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_moderation_get_group_number(const Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
return group_moderation->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_moderation_set_source_peer_id(Tox_Event_Group_Moderation *group_moderation,
|
||||
uint32_t source_peer_id)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
group_moderation->source_peer_id = source_peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_moderation_get_source_peer_id(const Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
return group_moderation->source_peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_moderation_set_target_peer_id(Tox_Event_Group_Moderation *group_moderation,
|
||||
uint32_t target_peer_id)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
group_moderation->target_peer_id = target_peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_moderation_get_target_peer_id(const Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
return group_moderation->target_peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_moderation_set_mod_type(Tox_Event_Group_Moderation *group_moderation,
|
||||
Tox_Group_Mod_Event mod_type)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
group_moderation->mod_type = mod_type;
|
||||
}
|
||||
Tox_Group_Mod_Event tox_event_group_moderation_get_mod_type(const Tox_Event_Group_Moderation *group_moderation)
|
||||
{
|
||||
assert(group_moderation != nullptr);
|
||||
return group_moderation->mod_type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_moderation_pack(
|
||||
const Tox_Event_Group_Moderation *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_MODERATION)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->source_peer_id)
|
||||
&& bin_pack_u32(bp, event->target_peer_id)
|
||||
&& bin_pack_u32(bp, event->mod_type);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_moderation_unpack(
|
||||
Tox_Event_Group_Moderation *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->source_peer_id)
|
||||
&& bin_unpack_u32(bu, &event->target_peer_id)
|
||||
&& tox_unpack_group_mod_event(bu, &event->mod_type);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Moderation *tox_events_add_group_moderation(Tox_Events *events)
|
||||
{
|
||||
if (events->group_moderation_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_moderation_size == events->group_moderation_capacity) {
|
||||
const uint32_t new_group_moderation_capacity = events->group_moderation_capacity * 2 + 1;
|
||||
Tox_Event_Group_Moderation *new_group_moderation = (Tox_Event_Group_Moderation *)
|
||||
realloc(
|
||||
events->group_moderation,
|
||||
new_group_moderation_capacity * sizeof(Tox_Event_Group_Moderation));
|
||||
|
||||
if (new_group_moderation == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_moderation = new_group_moderation;
|
||||
events->group_moderation_capacity = new_group_moderation_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Moderation *const group_moderation =
|
||||
&events->group_moderation[events->group_moderation_size];
|
||||
tox_event_group_moderation_construct(group_moderation);
|
||||
++events->group_moderation_size;
|
||||
return group_moderation;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_moderation(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_moderation_size; ++i) {
|
||||
tox_event_group_moderation_destruct(&events->group_moderation[i]);
|
||||
}
|
||||
|
||||
free(events->group_moderation);
|
||||
events->group_moderation = nullptr;
|
||||
events->group_moderation_size = 0;
|
||||
events->group_moderation_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_moderation_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_moderation_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Moderation *tox_events_get_group_moderation(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_moderation_size);
|
||||
assert(events->group_moderation != nullptr);
|
||||
return &events->group_moderation[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_moderation(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_moderation_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_moderation_pack(tox_events_get_group_moderation(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_moderation(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Moderation *event = tox_events_add_group_moderation(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_moderation_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_moderation(Tox *tox, uint32_t group_number, uint32_t source_peer_id, uint32_t target_peer_id, Tox_Group_Mod_Event mod_type,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Moderation *group_moderation = tox_events_add_group_moderation(state->events);
|
||||
|
||||
if (group_moderation == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_moderation_set_group_number(group_moderation, group_number);
|
||||
tox_event_group_moderation_set_source_peer_id(group_moderation, source_peer_id);
|
||||
tox_event_group_moderation_set_target_peer_id(group_moderation, target_peer_id);
|
||||
tox_event_group_moderation_set_mod_type(group_moderation, mod_type);
|
||||
}
|
235
external/toxcore/c-toxcore/toxcore/events/group_password.c
vendored
Normal file
235
external/toxcore/c-toxcore/toxcore/events/group_password.c
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Password {
|
||||
uint32_t group_number;
|
||||
uint8_t *password;
|
||||
uint32_t password_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_password_construct(Tox_Event_Group_Password *group_password)
|
||||
{
|
||||
*group_password = (Tox_Event_Group_Password) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_password_destruct(Tox_Event_Group_Password *group_password)
|
||||
{
|
||||
free(group_password->password);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_password_set_group_number(Tox_Event_Group_Password *group_password,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_password != nullptr);
|
||||
group_password->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_password_get_group_number(const Tox_Event_Group_Password *group_password)
|
||||
{
|
||||
assert(group_password != nullptr);
|
||||
return group_password->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_password_set_password(Tox_Event_Group_Password *group_password,
|
||||
const uint8_t *password, uint32_t password_length)
|
||||
{
|
||||
assert(group_password != nullptr);
|
||||
|
||||
if (group_password->password != nullptr) {
|
||||
free(group_password->password);
|
||||
group_password->password = nullptr;
|
||||
group_password->password_length = 0;
|
||||
}
|
||||
|
||||
group_password->password = (uint8_t *)malloc(password_length);
|
||||
|
||||
if (group_password->password == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_password->password, password, password_length);
|
||||
group_password->password_length = password_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_password_get_password_length(const Tox_Event_Group_Password *group_password)
|
||||
{
|
||||
assert(group_password != nullptr);
|
||||
return group_password->password_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_password_get_password(const Tox_Event_Group_Password *group_password)
|
||||
{
|
||||
assert(group_password != nullptr);
|
||||
return group_password->password;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_password_pack(
|
||||
const Tox_Event_Group_Password *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PASSWORD)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_bin(bp, event->password, event->password_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_password_unpack(
|
||||
Tox_Event_Group_Password *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_bin(bu, &event->password, &event->password_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Password *tox_events_add_group_password(Tox_Events *events)
|
||||
{
|
||||
if (events->group_password_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_password_size == events->group_password_capacity) {
|
||||
const uint32_t new_group_password_capacity = events->group_password_capacity * 2 + 1;
|
||||
Tox_Event_Group_Password *new_group_password = (Tox_Event_Group_Password *)
|
||||
realloc(
|
||||
events->group_password,
|
||||
new_group_password_capacity * sizeof(Tox_Event_Group_Password));
|
||||
|
||||
if (new_group_password == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_password = new_group_password;
|
||||
events->group_password_capacity = new_group_password_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Password *const group_password =
|
||||
&events->group_password[events->group_password_size];
|
||||
tox_event_group_password_construct(group_password);
|
||||
++events->group_password_size;
|
||||
return group_password;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_password(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_password_size; ++i) {
|
||||
tox_event_group_password_destruct(&events->group_password[i]);
|
||||
}
|
||||
|
||||
free(events->group_password);
|
||||
events->group_password = nullptr;
|
||||
events->group_password_size = 0;
|
||||
events->group_password_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_password_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_password_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Password *tox_events_get_group_password(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_password_size);
|
||||
assert(events->group_password != nullptr);
|
||||
return &events->group_password[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_password(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_password_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_password_pack(tox_events_get_group_password(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_password(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Password *event = tox_events_add_group_password(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_password_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_password(Tox *tox, uint32_t group_number, const uint8_t *password, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Password *group_password = tox_events_add_group_password(state->events);
|
||||
|
||||
if (group_password == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_password_set_group_number(group_password, group_number);
|
||||
tox_event_group_password_set_password(group_password, password, length);
|
||||
}
|
308
external/toxcore/c-toxcore/toxcore/events/group_peer_exit.c
vendored
Normal file
308
external/toxcore/c-toxcore/toxcore/events/group_peer_exit.c
vendored
Normal file
@ -0,0 +1,308 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Peer_Exit {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
Tox_Group_Exit_Type exit_type;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
uint8_t *part_message;
|
||||
uint32_t part_message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_exit_construct(Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
*group_peer_exit = (Tox_Event_Group_Peer_Exit) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_peer_exit_destruct(Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
free(group_peer_exit->name);
|
||||
free(group_peer_exit->part_message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_exit_set_group_number(Tox_Event_Group_Peer_Exit *group_peer_exit,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
group_peer_exit->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_peer_exit_get_group_number(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_exit_set_peer_id(Tox_Event_Group_Peer_Exit *group_peer_exit,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
group_peer_exit->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_peer_exit_get_peer_id(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_exit_set_exit_type(Tox_Event_Group_Peer_Exit *group_peer_exit,
|
||||
Tox_Group_Exit_Type exit_type)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
group_peer_exit->exit_type = exit_type;
|
||||
}
|
||||
Tox_Group_Exit_Type tox_event_group_peer_exit_get_exit_type(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->exit_type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_exit_set_name(Tox_Event_Group_Peer_Exit *group_peer_exit,
|
||||
const uint8_t *name, uint32_t name_length)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
|
||||
if (group_peer_exit->name != nullptr) {
|
||||
free(group_peer_exit->name);
|
||||
group_peer_exit->name = nullptr;
|
||||
group_peer_exit->name_length = 0;
|
||||
}
|
||||
|
||||
group_peer_exit->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (group_peer_exit->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_peer_exit->name, name, name_length);
|
||||
group_peer_exit->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_peer_exit_get_name_length(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_peer_exit_get_name(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_exit_set_part_message(Tox_Event_Group_Peer_Exit *group_peer_exit,
|
||||
const uint8_t *part_message, uint32_t part_message_length)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
|
||||
if (group_peer_exit->part_message != nullptr) {
|
||||
free(group_peer_exit->part_message);
|
||||
group_peer_exit->part_message = nullptr;
|
||||
group_peer_exit->part_message_length = 0;
|
||||
}
|
||||
|
||||
group_peer_exit->part_message = (uint8_t *)malloc(part_message_length);
|
||||
|
||||
if (group_peer_exit->part_message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_peer_exit->part_message, part_message, part_message_length);
|
||||
group_peer_exit->part_message_length = part_message_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_peer_exit_get_part_message_length(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->part_message_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_peer_exit_get_part_message(const Tox_Event_Group_Peer_Exit *group_peer_exit)
|
||||
{
|
||||
assert(group_peer_exit != nullptr);
|
||||
return group_peer_exit->part_message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_exit_pack(
|
||||
const Tox_Event_Group_Peer_Exit *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PEER_EXIT)
|
||||
&& bin_pack_array(bp, 5)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_u32(bp, event->exit_type)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length)
|
||||
&& bin_pack_bin(bp, event->part_message, event->part_message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_exit_unpack(
|
||||
Tox_Event_Group_Peer_Exit *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& tox_unpack_group_exit_type(bu, &event->exit_type)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length)
|
||||
&& bin_unpack_bin(bu, &event->part_message, &event->part_message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Peer_Exit *tox_events_add_group_peer_exit(Tox_Events *events)
|
||||
{
|
||||
if (events->group_peer_exit_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_peer_exit_size == events->group_peer_exit_capacity) {
|
||||
const uint32_t new_group_peer_exit_capacity = events->group_peer_exit_capacity * 2 + 1;
|
||||
Tox_Event_Group_Peer_Exit *new_group_peer_exit = (Tox_Event_Group_Peer_Exit *)
|
||||
realloc(
|
||||
events->group_peer_exit,
|
||||
new_group_peer_exit_capacity * sizeof(Tox_Event_Group_Peer_Exit));
|
||||
|
||||
if (new_group_peer_exit == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_peer_exit = new_group_peer_exit;
|
||||
events->group_peer_exit_capacity = new_group_peer_exit_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Exit *const group_peer_exit =
|
||||
&events->group_peer_exit[events->group_peer_exit_size];
|
||||
tox_event_group_peer_exit_construct(group_peer_exit);
|
||||
++events->group_peer_exit_size;
|
||||
return group_peer_exit;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_peer_exit(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_peer_exit_size; ++i) {
|
||||
tox_event_group_peer_exit_destruct(&events->group_peer_exit[i]);
|
||||
}
|
||||
|
||||
free(events->group_peer_exit);
|
||||
events->group_peer_exit = nullptr;
|
||||
events->group_peer_exit_size = 0;
|
||||
events->group_peer_exit_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_peer_exit_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_peer_exit_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Peer_Exit *tox_events_get_group_peer_exit(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_peer_exit_size);
|
||||
assert(events->group_peer_exit != nullptr);
|
||||
return &events->group_peer_exit[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_peer_exit(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_peer_exit_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_peer_exit_pack(tox_events_get_group_peer_exit(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_peer_exit(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Peer_Exit *event = tox_events_add_group_peer_exit(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_peer_exit_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_peer_exit(Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Group_Exit_Type exit_type, const uint8_t *name, size_t name_length, const uint8_t *part_message, size_t part_message_length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Exit *group_peer_exit = tox_events_add_group_peer_exit(state->events);
|
||||
|
||||
if (group_peer_exit == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_peer_exit_set_group_number(group_peer_exit, group_number);
|
||||
tox_event_group_peer_exit_set_peer_id(group_peer_exit, peer_id);
|
||||
tox_event_group_peer_exit_set_exit_type(group_peer_exit, exit_type);
|
||||
tox_event_group_peer_exit_set_name(group_peer_exit, name, name_length);
|
||||
tox_event_group_peer_exit_set_part_message(group_peer_exit, part_message, part_message_length);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_peer_join.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_peer_join.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Peer_Join {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_join_construct(Tox_Event_Group_Peer_Join *group_peer_join)
|
||||
{
|
||||
*group_peer_join = (Tox_Event_Group_Peer_Join) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_peer_join_destruct(Tox_Event_Group_Peer_Join *group_peer_join)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_join_set_group_number(Tox_Event_Group_Peer_Join *group_peer_join,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_peer_join != nullptr);
|
||||
group_peer_join->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_peer_join_get_group_number(const Tox_Event_Group_Peer_Join *group_peer_join)
|
||||
{
|
||||
assert(group_peer_join != nullptr);
|
||||
return group_peer_join->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_join_set_peer_id(Tox_Event_Group_Peer_Join *group_peer_join,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_peer_join != nullptr);
|
||||
group_peer_join->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_peer_join_get_peer_id(const Tox_Event_Group_Peer_Join *group_peer_join)
|
||||
{
|
||||
assert(group_peer_join != nullptr);
|
||||
return group_peer_join->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_join_pack(
|
||||
const Tox_Event_Group_Peer_Join *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PEER_JOIN)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_join_unpack(
|
||||
Tox_Event_Group_Peer_Join *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Peer_Join *tox_events_add_group_peer_join(Tox_Events *events)
|
||||
{
|
||||
if (events->group_peer_join_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_peer_join_size == events->group_peer_join_capacity) {
|
||||
const uint32_t new_group_peer_join_capacity = events->group_peer_join_capacity * 2 + 1;
|
||||
Tox_Event_Group_Peer_Join *new_group_peer_join = (Tox_Event_Group_Peer_Join *)
|
||||
realloc(
|
||||
events->group_peer_join,
|
||||
new_group_peer_join_capacity * sizeof(Tox_Event_Group_Peer_Join));
|
||||
|
||||
if (new_group_peer_join == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_peer_join = new_group_peer_join;
|
||||
events->group_peer_join_capacity = new_group_peer_join_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Join *const group_peer_join =
|
||||
&events->group_peer_join[events->group_peer_join_size];
|
||||
tox_event_group_peer_join_construct(group_peer_join);
|
||||
++events->group_peer_join_size;
|
||||
return group_peer_join;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_peer_join(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_peer_join_size; ++i) {
|
||||
tox_event_group_peer_join_destruct(&events->group_peer_join[i]);
|
||||
}
|
||||
|
||||
free(events->group_peer_join);
|
||||
events->group_peer_join = nullptr;
|
||||
events->group_peer_join_size = 0;
|
||||
events->group_peer_join_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_peer_join_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_peer_join_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Peer_Join *tox_events_get_group_peer_join(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_peer_join_size);
|
||||
assert(events->group_peer_join != nullptr);
|
||||
return &events->group_peer_join[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_peer_join(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_peer_join_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_peer_join_pack(tox_events_get_group_peer_join(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_peer_join(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Peer_Join *event = tox_events_add_group_peer_join(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_peer_join_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_peer_join(Tox *tox, uint32_t group_number, uint32_t peer_id,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Join *group_peer_join = tox_events_add_group_peer_join(state->events);
|
||||
|
||||
if (group_peer_join == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_peer_join_set_group_number(group_peer_join, group_number);
|
||||
tox_event_group_peer_join_set_peer_id(group_peer_join, peer_id);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_peer_limit.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_peer_limit.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Peer_Limit {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_limit;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_limit_construct(Tox_Event_Group_Peer_Limit *group_peer_limit)
|
||||
{
|
||||
*group_peer_limit = (Tox_Event_Group_Peer_Limit) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_peer_limit_destruct(Tox_Event_Group_Peer_Limit *group_peer_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_limit_set_group_number(Tox_Event_Group_Peer_Limit *group_peer_limit,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_peer_limit != nullptr);
|
||||
group_peer_limit->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_peer_limit_get_group_number(const Tox_Event_Group_Peer_Limit *group_peer_limit)
|
||||
{
|
||||
assert(group_peer_limit != nullptr);
|
||||
return group_peer_limit->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_limit_set_peer_limit(Tox_Event_Group_Peer_Limit *group_peer_limit,
|
||||
uint32_t peer_limit)
|
||||
{
|
||||
assert(group_peer_limit != nullptr);
|
||||
group_peer_limit->peer_limit = peer_limit;
|
||||
}
|
||||
uint32_t tox_event_group_peer_limit_get_peer_limit(const Tox_Event_Group_Peer_Limit *group_peer_limit)
|
||||
{
|
||||
assert(group_peer_limit != nullptr);
|
||||
return group_peer_limit->peer_limit;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_limit_pack(
|
||||
const Tox_Event_Group_Peer_Limit *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PEER_LIMIT)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_limit);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_limit_unpack(
|
||||
Tox_Event_Group_Peer_Limit *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_limit);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Peer_Limit *tox_events_add_group_peer_limit(Tox_Events *events)
|
||||
{
|
||||
if (events->group_peer_limit_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_peer_limit_size == events->group_peer_limit_capacity) {
|
||||
const uint32_t new_group_peer_limit_capacity = events->group_peer_limit_capacity * 2 + 1;
|
||||
Tox_Event_Group_Peer_Limit *new_group_peer_limit = (Tox_Event_Group_Peer_Limit *)
|
||||
realloc(
|
||||
events->group_peer_limit,
|
||||
new_group_peer_limit_capacity * sizeof(Tox_Event_Group_Peer_Limit));
|
||||
|
||||
if (new_group_peer_limit == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_peer_limit = new_group_peer_limit;
|
||||
events->group_peer_limit_capacity = new_group_peer_limit_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Limit *const group_peer_limit =
|
||||
&events->group_peer_limit[events->group_peer_limit_size];
|
||||
tox_event_group_peer_limit_construct(group_peer_limit);
|
||||
++events->group_peer_limit_size;
|
||||
return group_peer_limit;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_peer_limit(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_peer_limit_size; ++i) {
|
||||
tox_event_group_peer_limit_destruct(&events->group_peer_limit[i]);
|
||||
}
|
||||
|
||||
free(events->group_peer_limit);
|
||||
events->group_peer_limit = nullptr;
|
||||
events->group_peer_limit_size = 0;
|
||||
events->group_peer_limit_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_peer_limit_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_peer_limit_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Peer_Limit *tox_events_get_group_peer_limit(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_peer_limit_size);
|
||||
assert(events->group_peer_limit != nullptr);
|
||||
return &events->group_peer_limit[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_peer_limit(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_peer_limit_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_peer_limit_pack(tox_events_get_group_peer_limit(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_peer_limit(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Peer_Limit *event = tox_events_add_group_peer_limit(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_peer_limit_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_peer_limit(Tox *tox, uint32_t group_number, uint32_t peer_limit,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Limit *group_peer_limit = tox_events_add_group_peer_limit(state->events);
|
||||
|
||||
if (group_peer_limit == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_peer_limit_set_group_number(group_peer_limit, group_number);
|
||||
tox_event_group_peer_limit_set_peer_limit(group_peer_limit, peer_limit);
|
||||
}
|
252
external/toxcore/c-toxcore/toxcore/events/group_peer_name.c
vendored
Normal file
252
external/toxcore/c-toxcore/toxcore/events/group_peer_name.c
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Peer_Name {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_name_construct(Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
*group_peer_name = (Tox_Event_Group_Peer_Name) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_peer_name_destruct(Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
free(group_peer_name->name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_name_set_group_number(Tox_Event_Group_Peer_Name *group_peer_name,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
group_peer_name->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_peer_name_get_group_number(const Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
return group_peer_name->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_name_set_peer_id(Tox_Event_Group_Peer_Name *group_peer_name,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
group_peer_name->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_peer_name_get_peer_id(const Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
return group_peer_name->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_name_set_name(Tox_Event_Group_Peer_Name *group_peer_name,
|
||||
const uint8_t *name, uint32_t name_length)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
|
||||
if (group_peer_name->name != nullptr) {
|
||||
free(group_peer_name->name);
|
||||
group_peer_name->name = nullptr;
|
||||
group_peer_name->name_length = 0;
|
||||
}
|
||||
|
||||
group_peer_name->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (group_peer_name->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_peer_name->name, name, name_length);
|
||||
group_peer_name->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_peer_name_get_name_length(const Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
return group_peer_name->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_peer_name_get_name(const Tox_Event_Group_Peer_Name *group_peer_name)
|
||||
{
|
||||
assert(group_peer_name != nullptr);
|
||||
return group_peer_name->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_name_pack(
|
||||
const Tox_Event_Group_Peer_Name *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PEER_NAME)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_name_unpack(
|
||||
Tox_Event_Group_Peer_Name *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Peer_Name *tox_events_add_group_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events->group_peer_name_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_peer_name_size == events->group_peer_name_capacity) {
|
||||
const uint32_t new_group_peer_name_capacity = events->group_peer_name_capacity * 2 + 1;
|
||||
Tox_Event_Group_Peer_Name *new_group_peer_name = (Tox_Event_Group_Peer_Name *)
|
||||
realloc(
|
||||
events->group_peer_name,
|
||||
new_group_peer_name_capacity * sizeof(Tox_Event_Group_Peer_Name));
|
||||
|
||||
if (new_group_peer_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_peer_name = new_group_peer_name;
|
||||
events->group_peer_name_capacity = new_group_peer_name_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Name *const group_peer_name =
|
||||
&events->group_peer_name[events->group_peer_name_size];
|
||||
tox_event_group_peer_name_construct(group_peer_name);
|
||||
++events->group_peer_name_size;
|
||||
return group_peer_name;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_peer_name_size; ++i) {
|
||||
tox_event_group_peer_name_destruct(&events->group_peer_name[i]);
|
||||
}
|
||||
|
||||
free(events->group_peer_name);
|
||||
events->group_peer_name = nullptr;
|
||||
events->group_peer_name_size = 0;
|
||||
events->group_peer_name_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_peer_name_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_peer_name_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Peer_Name *tox_events_get_group_peer_name(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_peer_name_size);
|
||||
assert(events->group_peer_name != nullptr);
|
||||
return &events->group_peer_name[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_peer_name(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_peer_name_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_peer_name_pack(tox_events_get_group_peer_name(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_peer_name(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Peer_Name *event = tox_events_add_group_peer_name(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_peer_name_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_peer_name(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Name *group_peer_name = tox_events_add_group_peer_name(state->events);
|
||||
|
||||
if (group_peer_name == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
231
external/toxcore/c-toxcore/toxcore/events/group_peer_status.c
vendored
Normal file
231
external/toxcore/c-toxcore/toxcore/events/group_peer_status.c
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Peer_Status {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
Tox_User_Status status;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_status_construct(Tox_Event_Group_Peer_Status *group_peer_status)
|
||||
{
|
||||
*group_peer_status = (Tox_Event_Group_Peer_Status) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_peer_status_destruct(Tox_Event_Group_Peer_Status *group_peer_status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_status_set_group_number(Tox_Event_Group_Peer_Status *group_peer_status,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
group_peer_status->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_peer_status_get_group_number(const Tox_Event_Group_Peer_Status *group_peer_status)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
return group_peer_status->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_status_set_peer_id(Tox_Event_Group_Peer_Status *group_peer_status,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
group_peer_status->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_peer_status_get_peer_id(const Tox_Event_Group_Peer_Status *group_peer_status)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
return group_peer_status->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_peer_status_set_status(Tox_Event_Group_Peer_Status *group_peer_status,
|
||||
Tox_User_Status status)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
group_peer_status->status = status;
|
||||
}
|
||||
Tox_User_Status tox_event_group_peer_status_get_status(const Tox_Event_Group_Peer_Status *group_peer_status)
|
||||
{
|
||||
assert(group_peer_status != nullptr);
|
||||
return group_peer_status->status;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_status_pack(
|
||||
const Tox_Event_Group_Peer_Status *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PEER_STATUS)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_u32(bp, event->status);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_peer_status_unpack(
|
||||
Tox_Event_Group_Peer_Status *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& tox_unpack_user_status(bu, &event->status);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Peer_Status *tox_events_add_group_peer_status(Tox_Events *events)
|
||||
{
|
||||
if (events->group_peer_status_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_peer_status_size == events->group_peer_status_capacity) {
|
||||
const uint32_t new_group_peer_status_capacity = events->group_peer_status_capacity * 2 + 1;
|
||||
Tox_Event_Group_Peer_Status *new_group_peer_status = (Tox_Event_Group_Peer_Status *)
|
||||
realloc(
|
||||
events->group_peer_status,
|
||||
new_group_peer_status_capacity * sizeof(Tox_Event_Group_Peer_Status));
|
||||
|
||||
if (new_group_peer_status == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_peer_status = new_group_peer_status;
|
||||
events->group_peer_status_capacity = new_group_peer_status_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Status *const group_peer_status =
|
||||
&events->group_peer_status[events->group_peer_status_size];
|
||||
tox_event_group_peer_status_construct(group_peer_status);
|
||||
++events->group_peer_status_size;
|
||||
return group_peer_status;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_peer_status(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_peer_status_size; ++i) {
|
||||
tox_event_group_peer_status_destruct(&events->group_peer_status[i]);
|
||||
}
|
||||
|
||||
free(events->group_peer_status);
|
||||
events->group_peer_status = nullptr;
|
||||
events->group_peer_status_size = 0;
|
||||
events->group_peer_status_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_peer_status_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_peer_status_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Peer_Status *tox_events_get_group_peer_status(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_peer_status_size);
|
||||
assert(events->group_peer_status != nullptr);
|
||||
return &events->group_peer_status[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_peer_status(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_peer_status_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_peer_status_pack(tox_events_get_group_peer_status(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_peer_status(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Peer_Status *event = tox_events_add_group_peer_status(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_peer_status_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_peer_status(Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_User_Status status,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Peer_Status *group_peer_status = tox_events_add_group_peer_status(state->events);
|
||||
|
||||
if (group_peer_status == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_peer_status_set_group_number(group_peer_status, group_number);
|
||||
tox_event_group_peer_status_set_peer_id(group_peer_status, peer_id);
|
||||
tox_event_group_peer_status_set_status(group_peer_status, status);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_privacy_state.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_privacy_state.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Privacy_State {
|
||||
uint32_t group_number;
|
||||
Tox_Group_Privacy_State privacy_state;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_privacy_state_construct(Tox_Event_Group_Privacy_State *group_privacy_state)
|
||||
{
|
||||
*group_privacy_state = (Tox_Event_Group_Privacy_State) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_privacy_state_destruct(Tox_Event_Group_Privacy_State *group_privacy_state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_privacy_state_set_group_number(Tox_Event_Group_Privacy_State *group_privacy_state,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_privacy_state != nullptr);
|
||||
group_privacy_state->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_privacy_state_get_group_number(const Tox_Event_Group_Privacy_State *group_privacy_state)
|
||||
{
|
||||
assert(group_privacy_state != nullptr);
|
||||
return group_privacy_state->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_privacy_state_set_privacy_state(Tox_Event_Group_Privacy_State *group_privacy_state,
|
||||
Tox_Group_Privacy_State privacy_state)
|
||||
{
|
||||
assert(group_privacy_state != nullptr);
|
||||
group_privacy_state->privacy_state = privacy_state;
|
||||
}
|
||||
Tox_Group_Privacy_State tox_event_group_privacy_state_get_privacy_state(const Tox_Event_Group_Privacy_State *group_privacy_state)
|
||||
{
|
||||
assert(group_privacy_state != nullptr);
|
||||
return group_privacy_state->privacy_state;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_privacy_state_pack(
|
||||
const Tox_Event_Group_Privacy_State *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PRIVACY_STATE)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->privacy_state);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_privacy_state_unpack(
|
||||
Tox_Event_Group_Privacy_State *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& tox_unpack_group_privacy_state(bu, &event->privacy_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Privacy_State *tox_events_add_group_privacy_state(Tox_Events *events)
|
||||
{
|
||||
if (events->group_privacy_state_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_privacy_state_size == events->group_privacy_state_capacity) {
|
||||
const uint32_t new_group_privacy_state_capacity = events->group_privacy_state_capacity * 2 + 1;
|
||||
Tox_Event_Group_Privacy_State *new_group_privacy_state = (Tox_Event_Group_Privacy_State *)
|
||||
realloc(
|
||||
events->group_privacy_state,
|
||||
new_group_privacy_state_capacity * sizeof(Tox_Event_Group_Privacy_State));
|
||||
|
||||
if (new_group_privacy_state == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_privacy_state = new_group_privacy_state;
|
||||
events->group_privacy_state_capacity = new_group_privacy_state_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Privacy_State *const group_privacy_state =
|
||||
&events->group_privacy_state[events->group_privacy_state_size];
|
||||
tox_event_group_privacy_state_construct(group_privacy_state);
|
||||
++events->group_privacy_state_size;
|
||||
return group_privacy_state;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_privacy_state(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_privacy_state_size; ++i) {
|
||||
tox_event_group_privacy_state_destruct(&events->group_privacy_state[i]);
|
||||
}
|
||||
|
||||
free(events->group_privacy_state);
|
||||
events->group_privacy_state = nullptr;
|
||||
events->group_privacy_state_size = 0;
|
||||
events->group_privacy_state_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_privacy_state_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_privacy_state_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Privacy_State *tox_events_get_group_privacy_state(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_privacy_state_size);
|
||||
assert(events->group_privacy_state != nullptr);
|
||||
return &events->group_privacy_state[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_privacy_state(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_privacy_state_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_privacy_state_pack(tox_events_get_group_privacy_state(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_privacy_state(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Privacy_State *event = tox_events_add_group_privacy_state(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_privacy_state_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_privacy_state(Tox *tox, uint32_t group_number, Tox_Group_Privacy_State privacy_state,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Privacy_State *group_privacy_state = tox_events_add_group_privacy_state(state->events);
|
||||
|
||||
if (group_privacy_state == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_privacy_state_set_group_number(group_privacy_state, group_number);
|
||||
tox_event_group_privacy_state_set_privacy_state(group_privacy_state, privacy_state);
|
||||
}
|
269
external/toxcore/c-toxcore/toxcore/events/group_private_message.c
vendored
Normal file
269
external/toxcore/c-toxcore/toxcore/events/group_private_message.c
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Private_Message {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_private_message_construct(Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
*group_private_message = (Tox_Event_Group_Private_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_private_message_destruct(Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
free(group_private_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_private_message_set_group_number(Tox_Event_Group_Private_Message *group_private_message,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
group_private_message->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_private_message_get_group_number(const Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
return group_private_message->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_private_message_set_peer_id(Tox_Event_Group_Private_Message *group_private_message,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
group_private_message->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_private_message_get_peer_id(const Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
return group_private_message->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_private_message_set_type(Tox_Event_Group_Private_Message *group_private_message,
|
||||
Tox_Message_Type type)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
group_private_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_group_private_message_get_type(const Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
return group_private_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_private_message_set_message(Tox_Event_Group_Private_Message *group_private_message,
|
||||
const uint8_t *message, uint32_t message_length)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
|
||||
if (group_private_message->message != nullptr) {
|
||||
free(group_private_message->message);
|
||||
group_private_message->message = nullptr;
|
||||
group_private_message->message_length = 0;
|
||||
}
|
||||
|
||||
group_private_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (group_private_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_private_message->message, message, message_length);
|
||||
group_private_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_private_message_get_message_length(const Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
return group_private_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_private_message_get_message(const Tox_Event_Group_Private_Message *group_private_message)
|
||||
{
|
||||
assert(group_private_message != nullptr);
|
||||
return group_private_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_private_message_pack(
|
||||
const Tox_Event_Group_Private_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_PRIVATE_MESSAGE)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_private_message_unpack(
|
||||
Tox_Event_Group_Private_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Private_Message *tox_events_add_group_private_message(Tox_Events *events)
|
||||
{
|
||||
if (events->group_private_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_private_message_size == events->group_private_message_capacity) {
|
||||
const uint32_t new_group_private_message_capacity = events->group_private_message_capacity * 2 + 1;
|
||||
Tox_Event_Group_Private_Message *new_group_private_message = (Tox_Event_Group_Private_Message *)
|
||||
realloc(
|
||||
events->group_private_message,
|
||||
new_group_private_message_capacity * sizeof(Tox_Event_Group_Private_Message));
|
||||
|
||||
if (new_group_private_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_private_message = new_group_private_message;
|
||||
events->group_private_message_capacity = new_group_private_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Private_Message *const group_private_message =
|
||||
&events->group_private_message[events->group_private_message_size];
|
||||
tox_event_group_private_message_construct(group_private_message);
|
||||
++events->group_private_message_size;
|
||||
return group_private_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_private_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_private_message_size; ++i) {
|
||||
tox_event_group_private_message_destruct(&events->group_private_message[i]);
|
||||
}
|
||||
|
||||
free(events->group_private_message);
|
||||
events->group_private_message = nullptr;
|
||||
events->group_private_message_size = 0;
|
||||
events->group_private_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_private_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_private_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Private_Message *tox_events_get_group_private_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_private_message_size);
|
||||
assert(events->group_private_message != nullptr);
|
||||
return &events->group_private_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_private_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_private_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_private_message_pack(tox_events_get_group_private_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_private_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Private_Message *event = tox_events_add_group_private_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_private_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
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,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Private_Message *group_private_message = tox_events_add_group_private_message(state->events);
|
||||
|
||||
if (group_private_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
193
external/toxcore/c-toxcore/toxcore/events/group_self_join.c
vendored
Normal file
193
external/toxcore/c-toxcore/toxcore/events/group_self_join.c
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Self_Join {
|
||||
uint32_t group_number;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_self_join_construct(Tox_Event_Group_Self_Join *group_self_join)
|
||||
{
|
||||
*group_self_join = (Tox_Event_Group_Self_Join) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_self_join_destruct(Tox_Event_Group_Self_Join *group_self_join)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_self_join_set_group_number(Tox_Event_Group_Self_Join *group_self_join,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_self_join != nullptr);
|
||||
group_self_join->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_self_join_get_group_number(const Tox_Event_Group_Self_Join *group_self_join)
|
||||
{
|
||||
assert(group_self_join != nullptr);
|
||||
return group_self_join->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_self_join_pack(
|
||||
const Tox_Event_Group_Self_Join *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_SELF_JOIN)
|
||||
|
||||
&& bin_pack_u32(bp, event->group_number);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_self_join_unpack(
|
||||
Tox_Event_Group_Self_Join *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_unpack_u32(bu, &event->group_number);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Self_Join *tox_events_add_group_self_join(Tox_Events *events)
|
||||
{
|
||||
if (events->group_self_join_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_self_join_size == events->group_self_join_capacity) {
|
||||
const uint32_t new_group_self_join_capacity = events->group_self_join_capacity * 2 + 1;
|
||||
Tox_Event_Group_Self_Join *new_group_self_join = (Tox_Event_Group_Self_Join *)
|
||||
realloc(
|
||||
events->group_self_join,
|
||||
new_group_self_join_capacity * sizeof(Tox_Event_Group_Self_Join));
|
||||
|
||||
if (new_group_self_join == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_self_join = new_group_self_join;
|
||||
events->group_self_join_capacity = new_group_self_join_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Self_Join *const group_self_join =
|
||||
&events->group_self_join[events->group_self_join_size];
|
||||
tox_event_group_self_join_construct(group_self_join);
|
||||
++events->group_self_join_size;
|
||||
return group_self_join;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_self_join(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_self_join_size; ++i) {
|
||||
tox_event_group_self_join_destruct(&events->group_self_join[i]);
|
||||
}
|
||||
|
||||
free(events->group_self_join);
|
||||
events->group_self_join = nullptr;
|
||||
events->group_self_join_size = 0;
|
||||
events->group_self_join_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_self_join_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_self_join_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Self_Join *tox_events_get_group_self_join(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_self_join_size);
|
||||
assert(events->group_self_join != nullptr);
|
||||
return &events->group_self_join[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_self_join(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_self_join_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_self_join_pack(tox_events_get_group_self_join(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_self_join(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Self_Join *event = tox_events_add_group_self_join(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_self_join_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_self_join(Tox *tox, uint32_t group_number,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Self_Join *group_self_join = tox_events_add_group_self_join(state->events);
|
||||
|
||||
if (group_self_join == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_self_join_set_group_number(group_self_join, group_number);
|
||||
}
|
252
external/toxcore/c-toxcore/toxcore/events/group_topic.c
vendored
Normal file
252
external/toxcore/c-toxcore/toxcore/events/group_topic.c
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Topic {
|
||||
uint32_t group_number;
|
||||
uint32_t peer_id;
|
||||
uint8_t *topic;
|
||||
uint32_t topic_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_construct(Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
*group_topic = (Tox_Event_Group_Topic) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_topic_destruct(Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
free(group_topic->topic);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_set_group_number(Tox_Event_Group_Topic *group_topic,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
group_topic->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_topic_get_group_number(const Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
return group_topic->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_set_peer_id(Tox_Event_Group_Topic *group_topic,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
group_topic->peer_id = peer_id;
|
||||
}
|
||||
uint32_t tox_event_group_topic_get_peer_id(const Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
return group_topic->peer_id;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_topic_set_topic(Tox_Event_Group_Topic *group_topic,
|
||||
const uint8_t *topic, uint32_t topic_length)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
|
||||
if (group_topic->topic != nullptr) {
|
||||
free(group_topic->topic);
|
||||
group_topic->topic = nullptr;
|
||||
group_topic->topic_length = 0;
|
||||
}
|
||||
|
||||
group_topic->topic = (uint8_t *)malloc(topic_length);
|
||||
|
||||
if (group_topic->topic == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(group_topic->topic, topic, topic_length);
|
||||
group_topic->topic_length = topic_length;
|
||||
return true;
|
||||
}
|
||||
size_t tox_event_group_topic_get_topic_length(const Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
return group_topic->topic_length;
|
||||
}
|
||||
const uint8_t *tox_event_group_topic_get_topic(const Tox_Event_Group_Topic *group_topic)
|
||||
{
|
||||
assert(group_topic != nullptr);
|
||||
return group_topic->topic;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_topic_pack(
|
||||
const Tox_Event_Group_Topic *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_TOPIC)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->peer_id)
|
||||
&& bin_pack_bin(bp, event->topic, event->topic_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_topic_unpack(
|
||||
Tox_Event_Group_Topic *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_id)
|
||||
&& bin_unpack_bin(bu, &event->topic, &event->topic_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Topic *tox_events_add_group_topic(Tox_Events *events)
|
||||
{
|
||||
if (events->group_topic_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_topic_size == events->group_topic_capacity) {
|
||||
const uint32_t new_group_topic_capacity = events->group_topic_capacity * 2 + 1;
|
||||
Tox_Event_Group_Topic *new_group_topic = (Tox_Event_Group_Topic *)
|
||||
realloc(
|
||||
events->group_topic,
|
||||
new_group_topic_capacity * sizeof(Tox_Event_Group_Topic));
|
||||
|
||||
if (new_group_topic == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_topic = new_group_topic;
|
||||
events->group_topic_capacity = new_group_topic_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Topic *const group_topic =
|
||||
&events->group_topic[events->group_topic_size];
|
||||
tox_event_group_topic_construct(group_topic);
|
||||
++events->group_topic_size;
|
||||
return group_topic;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_topic(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_topic_size; ++i) {
|
||||
tox_event_group_topic_destruct(&events->group_topic[i]);
|
||||
}
|
||||
|
||||
free(events->group_topic);
|
||||
events->group_topic = nullptr;
|
||||
events->group_topic_size = 0;
|
||||
events->group_topic_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_topic_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_topic_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Topic *tox_events_get_group_topic(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_topic_size);
|
||||
assert(events->group_topic != nullptr);
|
||||
return &events->group_topic[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_topic(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_topic_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_topic_pack(tox_events_get_group_topic(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_topic(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Topic *event = tox_events_add_group_topic(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_topic_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_topic(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Topic *group_topic = tox_events_add_group_topic(state->events);
|
||||
|
||||
if (group_topic == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_topic_lock.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_topic_lock.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Topic_Lock {
|
||||
uint32_t group_number;
|
||||
Tox_Group_Topic_Lock topic_lock;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_lock_construct(Tox_Event_Group_Topic_Lock *group_topic_lock)
|
||||
{
|
||||
*group_topic_lock = (Tox_Event_Group_Topic_Lock) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_topic_lock_destruct(Tox_Event_Group_Topic_Lock *group_topic_lock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_lock_set_group_number(Tox_Event_Group_Topic_Lock *group_topic_lock,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_topic_lock != nullptr);
|
||||
group_topic_lock->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_topic_lock_get_group_number(const Tox_Event_Group_Topic_Lock *group_topic_lock)
|
||||
{
|
||||
assert(group_topic_lock != nullptr);
|
||||
return group_topic_lock->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_topic_lock_set_topic_lock(Tox_Event_Group_Topic_Lock *group_topic_lock,
|
||||
Tox_Group_Topic_Lock topic_lock)
|
||||
{
|
||||
assert(group_topic_lock != nullptr);
|
||||
group_topic_lock->topic_lock = topic_lock;
|
||||
}
|
||||
Tox_Group_Topic_Lock tox_event_group_topic_lock_get_topic_lock(const Tox_Event_Group_Topic_Lock *group_topic_lock)
|
||||
{
|
||||
assert(group_topic_lock != nullptr);
|
||||
return group_topic_lock->topic_lock;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_topic_lock_pack(
|
||||
const Tox_Event_Group_Topic_Lock *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_TOPIC_LOCK)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->topic_lock);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_topic_lock_unpack(
|
||||
Tox_Event_Group_Topic_Lock *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& tox_unpack_group_topic_lock(bu, &event->topic_lock);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Topic_Lock *tox_events_add_group_topic_lock(Tox_Events *events)
|
||||
{
|
||||
if (events->group_topic_lock_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_topic_lock_size == events->group_topic_lock_capacity) {
|
||||
const uint32_t new_group_topic_lock_capacity = events->group_topic_lock_capacity * 2 + 1;
|
||||
Tox_Event_Group_Topic_Lock *new_group_topic_lock = (Tox_Event_Group_Topic_Lock *)
|
||||
realloc(
|
||||
events->group_topic_lock,
|
||||
new_group_topic_lock_capacity * sizeof(Tox_Event_Group_Topic_Lock));
|
||||
|
||||
if (new_group_topic_lock == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_topic_lock = new_group_topic_lock;
|
||||
events->group_topic_lock_capacity = new_group_topic_lock_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Topic_Lock *const group_topic_lock =
|
||||
&events->group_topic_lock[events->group_topic_lock_size];
|
||||
tox_event_group_topic_lock_construct(group_topic_lock);
|
||||
++events->group_topic_lock_size;
|
||||
return group_topic_lock;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_topic_lock(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_topic_lock_size; ++i) {
|
||||
tox_event_group_topic_lock_destruct(&events->group_topic_lock[i]);
|
||||
}
|
||||
|
||||
free(events->group_topic_lock);
|
||||
events->group_topic_lock = nullptr;
|
||||
events->group_topic_lock_size = 0;
|
||||
events->group_topic_lock_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_topic_lock_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_topic_lock_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Topic_Lock *tox_events_get_group_topic_lock(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_topic_lock_size);
|
||||
assert(events->group_topic_lock != nullptr);
|
||||
return &events->group_topic_lock[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_topic_lock(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_topic_lock_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_topic_lock_pack(tox_events_get_group_topic_lock(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_topic_lock(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Topic_Lock *event = tox_events_add_group_topic_lock(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_topic_lock_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_topic_lock(Tox *tox, uint32_t group_number, Tox_Group_Topic_Lock topic_lock,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Topic_Lock *group_topic_lock = tox_events_add_group_topic_lock(state->events);
|
||||
|
||||
if (group_topic_lock == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_topic_lock_set_group_number(group_topic_lock, group_number);
|
||||
tox_event_group_topic_lock_set_topic_lock(group_topic_lock, topic_lock);
|
||||
}
|
214
external/toxcore/c-toxcore/toxcore/events/group_voice_state.c
vendored
Normal file
214
external/toxcore/c-toxcore/toxcore/events/group_voice_state.c
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2023 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Group_Voice_State {
|
||||
uint32_t group_number;
|
||||
Tox_Group_Voice_State voice_state;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_voice_state_construct(Tox_Event_Group_Voice_State *group_voice_state)
|
||||
{
|
||||
*group_voice_state = (Tox_Event_Group_Voice_State) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_group_voice_state_destruct(Tox_Event_Group_Voice_State *group_voice_state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_voice_state_set_group_number(Tox_Event_Group_Voice_State *group_voice_state,
|
||||
uint32_t group_number)
|
||||
{
|
||||
assert(group_voice_state != nullptr);
|
||||
group_voice_state->group_number = group_number;
|
||||
}
|
||||
uint32_t tox_event_group_voice_state_get_group_number(const Tox_Event_Group_Voice_State *group_voice_state)
|
||||
{
|
||||
assert(group_voice_state != nullptr);
|
||||
return group_voice_state->group_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_group_voice_state_set_voice_state(Tox_Event_Group_Voice_State *group_voice_state,
|
||||
Tox_Group_Voice_State voice_state)
|
||||
{
|
||||
assert(group_voice_state != nullptr);
|
||||
group_voice_state->voice_state = voice_state;
|
||||
}
|
||||
Tox_Group_Voice_State tox_event_group_voice_state_get_voice_state(const Tox_Event_Group_Voice_State *group_voice_state)
|
||||
{
|
||||
assert(group_voice_state != nullptr);
|
||||
return group_voice_state->voice_state;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_voice_state_pack(
|
||||
const Tox_Event_Group_Voice_State *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_GROUP_VOICE_STATE)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->group_number)
|
||||
&& bin_pack_u32(bp, event->voice_state);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_group_voice_state_unpack(
|
||||
Tox_Event_Group_Voice_State *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->group_number)
|
||||
&& tox_unpack_group_voice_state(bu, &event->voice_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Group_Voice_State *tox_events_add_group_voice_state(Tox_Events *events)
|
||||
{
|
||||
if (events->group_voice_state_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->group_voice_state_size == events->group_voice_state_capacity) {
|
||||
const uint32_t new_group_voice_state_capacity = events->group_voice_state_capacity * 2 + 1;
|
||||
Tox_Event_Group_Voice_State *new_group_voice_state = (Tox_Event_Group_Voice_State *)
|
||||
realloc(
|
||||
events->group_voice_state,
|
||||
new_group_voice_state_capacity * sizeof(Tox_Event_Group_Voice_State));
|
||||
|
||||
if (new_group_voice_state == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->group_voice_state = new_group_voice_state;
|
||||
events->group_voice_state_capacity = new_group_voice_state_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Voice_State *const group_voice_state =
|
||||
&events->group_voice_state[events->group_voice_state_size];
|
||||
tox_event_group_voice_state_construct(group_voice_state);
|
||||
++events->group_voice_state_size;
|
||||
return group_voice_state;
|
||||
}
|
||||
|
||||
void tox_events_clear_group_voice_state(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->group_voice_state_size; ++i) {
|
||||
tox_event_group_voice_state_destruct(&events->group_voice_state[i]);
|
||||
}
|
||||
|
||||
free(events->group_voice_state);
|
||||
events->group_voice_state = nullptr;
|
||||
events->group_voice_state_size = 0;
|
||||
events->group_voice_state_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_group_voice_state_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->group_voice_state_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Group_Voice_State *tox_events_get_group_voice_state(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->group_voice_state_size);
|
||||
assert(events->group_voice_state != nullptr);
|
||||
return &events->group_voice_state[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_group_voice_state(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_group_voice_state_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_group_voice_state_pack(tox_events_get_group_voice_state(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_group_voice_state(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Group_Voice_State *event = tox_events_add_group_voice_state(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_group_voice_state_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_group_voice_state(Tox *tox, uint32_t group_number, Tox_Group_Voice_State voice_state,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Group_Voice_State *group_voice_state = tox_events_add_group_voice_state(state->events);
|
||||
|
||||
if (group_voice_state == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_group_voice_state_set_group_number(group_voice_state, group_number);
|
||||
tox_event_group_voice_state_set_voice_state(group_voice_state, voice_state);
|
||||
}
|
190
external/toxcore/c-toxcore/toxcore/events/self_connection_status.c
vendored
Normal file
190
external/toxcore/c-toxcore/toxcore/events/self_connection_status.c
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Self_Connection_Status {
|
||||
Tox_Connection connection_status;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_self_connection_status_construct(Tox_Event_Self_Connection_Status *self_connection_status)
|
||||
{
|
||||
*self_connection_status = (Tox_Event_Self_Connection_Status) {
|
||||
TOX_CONNECTION_NONE
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_self_connection_status_destruct(Tox_Event_Self_Connection_Status *self_connection_status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_self_connection_status_set_connection_status(Tox_Event_Self_Connection_Status
|
||||
*self_connection_status, Tox_Connection connection_status)
|
||||
{
|
||||
assert(self_connection_status != nullptr);
|
||||
self_connection_status->connection_status = connection_status;
|
||||
}
|
||||
Tox_Connection tox_event_self_connection_status_get_connection_status(const Tox_Event_Self_Connection_Status
|
||||
*self_connection_status)
|
||||
{
|
||||
assert(self_connection_status != nullptr);
|
||||
return self_connection_status->connection_status;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_self_connection_status_pack(
|
||||
const Tox_Event_Self_Connection_Status *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_SELF_CONNECTION_STATUS)
|
||||
&& bin_pack_u32(bp, event->connection_status);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_self_connection_status_unpack(
|
||||
Tox_Event_Self_Connection_Status *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return tox_unpack_connection(bu, &event->connection_status);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Self_Connection_Status *tox_events_add_self_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events->self_connection_status_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->self_connection_status_size == events->self_connection_status_capacity) {
|
||||
const uint32_t new_self_connection_status_capacity = events->self_connection_status_capacity * 2 + 1;
|
||||
Tox_Event_Self_Connection_Status *new_self_connection_status = (Tox_Event_Self_Connection_Status *)realloc(
|
||||
events->self_connection_status, new_self_connection_status_capacity * sizeof(Tox_Event_Self_Connection_Status));
|
||||
|
||||
if (new_self_connection_status == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->self_connection_status = new_self_connection_status;
|
||||
events->self_connection_status_capacity = new_self_connection_status_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Self_Connection_Status *const self_connection_status =
|
||||
&events->self_connection_status[events->self_connection_status_size];
|
||||
tox_event_self_connection_status_construct(self_connection_status);
|
||||
++events->self_connection_status_size;
|
||||
return self_connection_status;
|
||||
}
|
||||
|
||||
void tox_events_clear_self_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->self_connection_status_size; ++i) {
|
||||
tox_event_self_connection_status_destruct(&events->self_connection_status[i]);
|
||||
}
|
||||
|
||||
free(events->self_connection_status);
|
||||
events->self_connection_status = nullptr;
|
||||
events->self_connection_status_size = 0;
|
||||
events->self_connection_status_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_self_connection_status_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->self_connection_status_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Self_Connection_Status *tox_events_get_self_connection_status(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->self_connection_status_size);
|
||||
assert(events->self_connection_status != nullptr);
|
||||
return &events->self_connection_status[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_self_connection_status(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_self_connection_status_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_self_connection_status_pack(tox_events_get_self_connection_status(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_self_connection_status(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Self_Connection_Status *event = tox_events_add_self_connection_status(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_self_connection_status_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_self_connection_status(Tox *tox, Tox_Connection connection_status, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Self_Connection_Status *self_connection_status = tox_events_add_self_connection_status(state->events);
|
||||
|
||||
if (self_connection_status == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_self_connection_status_set_connection_status(self_connection_status, connection_status);
|
||||
}
|
395
external/toxcore/c-toxcore/toxcore/forwarding.c
vendored
Normal file
395
external/toxcore/c-toxcore/toxcore/forwarding.c
vendored
Normal file
@ -0,0 +1,395 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2019-2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "forwarding.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "DHT.h"
|
||||
#include "ccompat.h"
|
||||
#include "timed_auth.h"
|
||||
|
||||
struct Forwarding {
|
||||
const Logger *log;
|
||||
const Random *rng;
|
||||
DHT *dht;
|
||||
const Mono_Time *mono_time;
|
||||
Networking_Core *net;
|
||||
|
||||
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
||||
|
||||
forward_reply_cb *forward_reply_callback;
|
||||
void *forward_reply_callback_object;
|
||||
|
||||
forwarded_request_cb *forwarded_request_callback;
|
||||
void *forwarded_request_callback_object;
|
||||
|
||||
forwarded_response_cb *forwarded_response_callback;
|
||||
void *forwarded_response_callback_object;
|
||||
};
|
||||
|
||||
DHT *forwarding_get_dht(Forwarding *forwarding)
|
||||
{
|
||||
return forwarding->dht;
|
||||
}
|
||||
|
||||
#define SENDBACK_TIMEOUT 3600
|
||||
|
||||
bool send_forward_request(Networking_Core *net, const IP_Port *forwarder,
|
||||
const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length)
|
||||
{
|
||||
if (chain_length == 0 || chain_length > MAX_FORWARD_CHAIN_LENGTH
|
||||
|| data_length > MAX_FORWARD_DATA_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t len = forward_chain_packet_size(chain_length, data_length);
|
||||
VLA(uint8_t, packet, len);
|
||||
|
||||
return create_forward_chain_packet(chain_keys, chain_length, data, data_length, packet)
|
||||
&& sendpacket(net, forwarder, packet, len) == len;
|
||||
}
|
||||
|
||||
uint16_t forward_chain_packet_size(uint16_t chain_length, uint16_t data_length)
|
||||
{
|
||||
return chain_length * (1 + CRYPTO_PUBLIC_KEY_SIZE) + data_length;
|
||||
}
|
||||
|
||||
bool create_forward_chain_packet(const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length,
|
||||
uint8_t *packet)
|
||||
{
|
||||
if (chain_length == 0 || chain_length > MAX_FORWARD_CHAIN_LENGTH
|
||||
|| data_length > MAX_FORWARD_DATA_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
|
||||
for (uint16_t j = 0; j < chain_length; ++j) {
|
||||
packet[offset] = NET_PACKET_FORWARD_REQUEST;
|
||||
++offset;
|
||||
memcpy(packet + offset, chain_keys + j * CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
offset += CRYPTO_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
memcpy(packet + offset, data, data_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint16_t forwarding_packet_length(uint16_t sendback_data_len, uint16_t data_length)
|
||||
{
|
||||
const uint16_t sendback_len = sendback_data_len == 0 ? 0 : TIMED_AUTH_SIZE + sendback_data_len;
|
||||
return 1 + 1 + sendback_len + data_length;
|
||||
}
|
||||
|
||||
non_null(1, 4, 6) nullable(2)
|
||||
static bool create_forwarding_packet(const Forwarding *forwarding,
|
||||
const uint8_t *sendback_data, uint16_t sendback_data_len,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *packet)
|
||||
{
|
||||
packet[0] = NET_PACKET_FORWARDING;
|
||||
|
||||
if (sendback_data_len == 0) {
|
||||
packet[1] = 0;
|
||||
memcpy(packet + 1 + 1, data, length);
|
||||
} else {
|
||||
const uint16_t sendback_len = TIMED_AUTH_SIZE + sendback_data_len;
|
||||
|
||||
if (sendback_len > MAX_SENDBACK_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
packet[1] = sendback_len;
|
||||
generate_timed_auth(forwarding->mono_time, SENDBACK_TIMEOUT, forwarding->hmac_key, sendback_data,
|
||||
sendback_data_len, packet + 1 + 1);
|
||||
|
||||
if (sendback_data_len != 0) {
|
||||
assert(sendback_data != nullptr);
|
||||
memcpy(packet + 1 + 1 + TIMED_AUTH_SIZE, sendback_data, sendback_data_len);
|
||||
}
|
||||
|
||||
memcpy(packet + 1 + 1 + sendback_len, data, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_forwarding(const Forwarding *forwarding, const IP_Port *dest,
|
||||
const uint8_t *sendback_data, uint16_t sendback_data_len,
|
||||
const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (length > MAX_FORWARD_DATA_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t len = forwarding_packet_length(sendback_data_len, length);
|
||||
VLA(uint8_t, packet, len);
|
||||
create_forwarding_packet(forwarding, sendback_data, sendback_data_len, data, length, packet);
|
||||
return sendpacket(forwarding->net, dest, packet, len) == len;
|
||||
}
|
||||
|
||||
#define FORWARD_REQUEST_MIN_PACKET_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE)
|
||||
|
||||
non_null(1) nullable(2, 4)
|
||||
static bool handle_forward_request_dht(const Forwarding *forwarding,
|
||||
const uint8_t *sendback_data, uint16_t sendback_data_len,
|
||||
const uint8_t *packet, uint16_t length)
|
||||
{
|
||||
if (length < FORWARD_REQUEST_MIN_PACKET_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *const public_key = packet + 1;
|
||||
const uint8_t *const forward_data = packet + (1 + CRYPTO_PUBLIC_KEY_SIZE);
|
||||
const uint16_t forward_data_len = length - (1 + CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
if (TIMED_AUTH_SIZE + sendback_data_len > MAX_SENDBACK_SIZE ||
|
||||
forward_data_len > MAX_FORWARD_DATA_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t len = forwarding_packet_length(sendback_data_len, forward_data_len);
|
||||
VLA(uint8_t, forwarding_packet, len);
|
||||
|
||||
create_forwarding_packet(forwarding, sendback_data, sendback_data_len, forward_data, forward_data_len,
|
||||
forwarding_packet);
|
||||
|
||||
return route_packet(forwarding->dht, public_key, forwarding_packet, len) == len;
|
||||
}
|
||||
|
||||
non_null(1, 2) nullable(3, 5)
|
||||
static int handle_forward_request(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
const Forwarding *forwarding = (const Forwarding *)object;
|
||||
|
||||
uint8_t sendback_data[1 + MAX_PACKED_IPPORT_SIZE];
|
||||
sendback_data[0] = SENDBACK_IPPORT;
|
||||
|
||||
const int ipport_length = pack_ip_port(forwarding->log, sendback_data + 1, MAX_PACKED_IPPORT_SIZE, source);
|
||||
|
||||
if (ipport_length == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return handle_forward_request_dht(forwarding, sendback_data, 1 + ipport_length, packet, length) ? 0 : 1;
|
||||
}
|
||||
|
||||
#define MIN_NONEMPTY_SENDBACK_SIZE TIMED_AUTH_SIZE
|
||||
#define FORWARD_REPLY_MIN_PACKET_SIZE (1 + 1 + MIN_NONEMPTY_SENDBACK_SIZE)
|
||||
|
||||
non_null(1, 2) nullable(3, 5)
|
||||
static int handle_forward_reply(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
const Forwarding *forwarding = (const Forwarding *)object;
|
||||
|
||||
if (length < FORWARD_REPLY_MIN_PACKET_SIZE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t sendback_len = packet[1];
|
||||
const uint8_t *const sendback_auth = packet + 1 + 1;
|
||||
const uint8_t *const sendback_data = sendback_auth + TIMED_AUTH_SIZE;
|
||||
|
||||
if (sendback_len > MAX_SENDBACK_SIZE) {
|
||||
/* value 0xff is reserved for possible future expansion */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sendback_len < TIMED_AUTH_SIZE + 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint16_t sendback_data_len = sendback_len - TIMED_AUTH_SIZE;
|
||||
|
||||
if (length < 1 + 1 + sendback_len) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t *const to_forward = packet + (1 + 1 + sendback_len);
|
||||
const uint16_t to_forward_len = length - (1 + 1 + sendback_len);
|
||||
|
||||
if (!check_timed_auth(forwarding->mono_time, SENDBACK_TIMEOUT, forwarding->hmac_key, sendback_data, sendback_data_len,
|
||||
sendback_auth)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sendback_data[0] == SENDBACK_IPPORT) {
|
||||
IP_Port dest;
|
||||
|
||||
if (unpack_ip_port(&dest, sendback_data + 1, sendback_data_len - 1, false)
|
||||
!= sendback_data_len - 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return send_forwarding(forwarding, &dest, nullptr, 0, to_forward, to_forward_len) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (sendback_data[0] == SENDBACK_FORWARD) {
|
||||
IP_Port forwarder;
|
||||
const int ipport_length = unpack_ip_port(&forwarder, sendback_data + 1, sendback_data_len - 1, false);
|
||||
|
||||
if (ipport_length == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t *const forward_sendback = sendback_data + (1 + ipport_length);
|
||||
const uint16_t forward_sendback_len = sendback_data_len - (1 + ipport_length);
|
||||
|
||||
return forward_reply(forwarding->net, &forwarder, forward_sendback, forward_sendback_len, to_forward,
|
||||
to_forward_len) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (forwarding->forward_reply_callback == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return forwarding->forward_reply_callback(forwarding->forward_reply_callback_object,
|
||||
sendback_data, sendback_data_len,
|
||||
to_forward, to_forward_len) ? 0 : 1;
|
||||
}
|
||||
|
||||
#define FORWARDING_MIN_PACKET_SIZE (1 + 1)
|
||||
|
||||
non_null(1, 2) nullable(3, 5)
|
||||
static int handle_forwarding(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
const Forwarding *forwarding = (const Forwarding *)object;
|
||||
|
||||
if (length < FORWARDING_MIN_PACKET_SIZE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t sendback_len = packet[1];
|
||||
|
||||
if (length < 1 + 1 + sendback_len) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t *const sendback = packet + 1 + 1;
|
||||
|
||||
const uint8_t *const forwarded = sendback + sendback_len;
|
||||
const uint16_t forwarded_len = length - (1 + 1 + sendback_len);
|
||||
|
||||
if (forwarded_len >= 1 && forwarded[0] == NET_PACKET_FORWARD_REQUEST) {
|
||||
VLA(uint8_t, sendback_data, 1 + MAX_PACKED_IPPORT_SIZE + sendback_len);
|
||||
sendback_data[0] = SENDBACK_FORWARD;
|
||||
|
||||
const int ipport_length = pack_ip_port(forwarding->log, sendback_data + 1, MAX_PACKED_IPPORT_SIZE, source);
|
||||
|
||||
if (ipport_length == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(sendback_data + 1 + ipport_length, sendback, sendback_len);
|
||||
|
||||
return handle_forward_request_dht(forwarding, sendback_data, 1 + ipport_length + sendback_len, forwarded,
|
||||
forwarded_len) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (sendback_len > 0) {
|
||||
if (forwarding->forwarded_request_callback == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
forwarding->forwarded_request_callback(forwarding->forwarded_request_callback_object,
|
||||
source, sendback, sendback_len,
|
||||
forwarded, forwarded_len, userdata);
|
||||
return 0;
|
||||
} else {
|
||||
if (forwarding->forwarded_response_callback == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
forwarding->forwarded_response_callback(forwarding->forwarded_response_callback_object,
|
||||
forwarded, forwarded_len, userdata);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool forward_reply(Networking_Core *net, const IP_Port *forwarder,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (sendback_length > MAX_SENDBACK_SIZE ||
|
||||
length > MAX_FORWARD_DATA_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t len = 1 + 1 + sendback_length + length;
|
||||
VLA(uint8_t, packet, len);
|
||||
packet[0] = NET_PACKET_FORWARD_REPLY;
|
||||
packet[1] = (uint8_t) sendback_length;
|
||||
memcpy(packet + 1 + 1, sendback, sendback_length);
|
||||
memcpy(packet + 1 + 1 + sendback_length, data, length);
|
||||
return sendpacket(net, forwarder, packet, len) == len;
|
||||
}
|
||||
|
||||
void set_callback_forwarded_request(Forwarding *forwarding, forwarded_request_cb *function, void *object)
|
||||
{
|
||||
forwarding->forwarded_request_callback = function;
|
||||
forwarding->forwarded_request_callback_object = object;
|
||||
}
|
||||
|
||||
void set_callback_forwarded_response(Forwarding *forwarding, forwarded_response_cb *function, void *object)
|
||||
{
|
||||
forwarding->forwarded_response_callback = function;
|
||||
forwarding->forwarded_response_callback_object = object;
|
||||
}
|
||||
|
||||
void set_callback_forward_reply(Forwarding *forwarding, forward_reply_cb *function, void *object)
|
||||
{
|
||||
forwarding->forward_reply_callback = function;
|
||||
forwarding->forward_reply_callback_object = object;
|
||||
}
|
||||
|
||||
Forwarding *new_forwarding(const Logger *log, const Random *rng, const Mono_Time *mono_time, DHT *dht)
|
||||
{
|
||||
if (log == nullptr || mono_time == nullptr || dht == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Forwarding *forwarding = (Forwarding *)calloc(1, sizeof(Forwarding));
|
||||
|
||||
if (forwarding == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
forwarding->log = log;
|
||||
forwarding->rng = rng;
|
||||
forwarding->mono_time = mono_time;
|
||||
forwarding->dht = dht;
|
||||
forwarding->net = dht_get_net(dht);
|
||||
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARD_REQUEST, &handle_forward_request, forwarding);
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARD_REPLY, &handle_forward_reply, forwarding);
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARDING, &handle_forwarding, forwarding);
|
||||
|
||||
new_hmac_key(forwarding->rng, forwarding->hmac_key);
|
||||
|
||||
return forwarding;
|
||||
}
|
||||
|
||||
void kill_forwarding(Forwarding *forwarding)
|
||||
{
|
||||
if (forwarding == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARD_REQUEST, nullptr, nullptr);
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARD_REPLY, nullptr, nullptr);
|
||||
networking_registerhandler(forwarding->net, NET_PACKET_FORWARDING, nullptr, nullptr);
|
||||
|
||||
crypto_memzero(forwarding->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
||||
|
||||
free(forwarding);
|
||||
}
|
125
external/toxcore/c-toxcore/toxcore/forwarding.h
vendored
Normal file
125
external/toxcore/c-toxcore/toxcore/forwarding.h
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2019-2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_FORWARDING_H
|
||||
#define C_TOXCORE_TOXCORE_FORWARDING_H
|
||||
|
||||
#include "DHT.h"
|
||||
#include "network.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SENDBACK_IPPORT 0
|
||||
#define SENDBACK_FORWARD 1
|
||||
#define SENDBACK_TCP 2
|
||||
|
||||
#define MAX_SENDBACK_SIZE (0xff - 1)
|
||||
#define MAX_FORWARD_DATA_SIZE (MAX_UDP_PACKET_SIZE - (1 + 1 + MAX_SENDBACK_SIZE))
|
||||
|
||||
#define MAX_FORWARD_CHAIN_LENGTH 4
|
||||
|
||||
#define MAX_PACKED_IPPORT_SIZE (1 + SIZE_IP6 + sizeof(uint16_t))
|
||||
|
||||
typedef struct Forwarding Forwarding;
|
||||
|
||||
non_null()
|
||||
DHT *forwarding_get_dht(Forwarding *forwarding);
|
||||
|
||||
/**
|
||||
* @brief Send data to forwarder for forwarding via chain of dht nodes.
|
||||
* Destination is last key in the chain.
|
||||
*
|
||||
* @param data Must be of length at most MAX_FORWARD_DATA_SIZE.
|
||||
* @param chain_length Number of intermediate nodes in chain.
|
||||
* Must be at least 1 and at most MAX_FORWARD_CHAIN_LENGTH.
|
||||
* @param chain_keys Public keys of chain nodes. Must be of length
|
||||
* `chain_length * CRYPTO_PUBLIC_KEY_SIZE`.
|
||||
*
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
non_null()
|
||||
bool send_forward_request(Networking_Core *net, const IP_Port *forwarder,
|
||||
const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length);
|
||||
|
||||
/** Returns size of packet written by create_forward_chain_packet. */
|
||||
uint16_t forward_chain_packet_size(uint16_t chain_length, uint16_t data_length);
|
||||
|
||||
/**
|
||||
* @brief Create forward request packet for forwarding data via chain of dht nodes.
|
||||
* Destination is last key in the chain.
|
||||
*
|
||||
* @param data Must be of length at most MAX_FORWARD_DATA_SIZE.
|
||||
* @param chain_length Number of intermediate nodes in chain.
|
||||
* Must be at least 1 and at most MAX_FORWARD_CHAIN_LENGTH.
|
||||
* @param chain_keys Public keys of chain nodes. Must be of length
|
||||
* `chain_length * CRYPTO_PUBLIC_KEY_SIZE`.
|
||||
* @param packet Must be of size at least
|
||||
* `forward_chain_packet_size(chain_length, data_length)` bytes.
|
||||
*
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
non_null()
|
||||
bool create_forward_chain_packet(const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length,
|
||||
uint8_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Send reply to forwarded packet via forwarder.
|
||||
* @param sendback Must be of size at most MAX_SENDBACK_SIZE.
|
||||
* @param data Must be of size at most MAX_FORWARD_DATA_SIZE.
|
||||
*
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
non_null()
|
||||
bool forward_reply(Networking_Core *net, const IP_Port *forwarder,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set callback to handle a forwarded request.
|
||||
* To reply to the packet, callback should use `forward_reply()` to send a reply
|
||||
* forwarded via forwarder, passing the provided sendback.
|
||||
*/
|
||||
typedef void forwarded_request_cb(void *object, const IP_Port *forwarder, const uint8_t *sendback,
|
||||
uint16_t sendback_length, const uint8_t *data,
|
||||
uint16_t length, void *userdata);
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_callback_forwarded_request(Forwarding *forwarding, forwarded_request_cb *function, void *object);
|
||||
|
||||
/** @brief Set callback to handle a forwarded response. */
|
||||
typedef void forwarded_response_cb(void *object, const uint8_t *data, uint16_t length, void *userdata);
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_callback_forwarded_response(Forwarding *forwarding, forwarded_response_cb *function, void *object);
|
||||
|
||||
/** @brief Send forwarding packet to dest with given sendback data and data. */
|
||||
non_null(1, 2, 5) nullable(3)
|
||||
bool send_forwarding(const Forwarding *forwarding, const IP_Port *dest,
|
||||
const uint8_t *sendback_data, uint16_t sendback_data_len,
|
||||
const uint8_t *data, uint16_t length);
|
||||
|
||||
typedef bool forward_reply_cb(void *object, const uint8_t *sendback_data, uint16_t sendback_data_len,
|
||||
const uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Set callback to handle a forward reply with an otherwise unhandled
|
||||
* sendback.
|
||||
*/
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_callback_forward_reply(Forwarding *forwarding, forward_reply_cb *function, void *object);
|
||||
|
||||
non_null()
|
||||
Forwarding *new_forwarding(const Logger *log, const Random *rng, const Mono_Time *mono_time, DHT *dht);
|
||||
|
||||
nullable(1)
|
||||
void kill_forwarding(Forwarding *forwarding);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
50
external/toxcore/c-toxcore/toxcore/forwarding_fuzz_test.cc
vendored
Normal file
50
external/toxcore/c-toxcore/toxcore/forwarding_fuzz_test.cc
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#include "forwarding.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "../testing/fuzzing/fuzz_support.h"
|
||||
#include "../testing/fuzzing/fuzz_tox.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TestSendForwardRequest(Fuzz_Data &input)
|
||||
{
|
||||
const Network *ns = system_network(); // TODO(iphydf): fuzz_network
|
||||
assert(ns != nullptr);
|
||||
|
||||
with<Logger>{} >> with<Networking_Core>{input, ns} >> [&input](Ptr<Networking_Core> net) {
|
||||
with<IP_Port>{input} >> [net = std::move(net), &input](const IP_Port &forwarder) {
|
||||
CONSUME1_OR_RETURN(const uint16_t chain_length, input);
|
||||
const uint16_t chain_keys_size = chain_length * CRYPTO_PUBLIC_KEY_SIZE;
|
||||
CONSUME_OR_RETURN(const uint8_t *chain_keys, input, chain_keys_size);
|
||||
|
||||
send_forward_request(
|
||||
net.get(), &forwarder, chain_keys, chain_length, input.data, input.size);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
void TestForwardReply(Fuzz_Data &input)
|
||||
{
|
||||
const Network *ns = system_network(); // TODO(iphydf): fuzz_network
|
||||
assert(ns != nullptr);
|
||||
|
||||
with<Logger>{} >> with<Networking_Core>{input, ns} >> [&input](Ptr<Networking_Core> net) {
|
||||
with<IP_Port>{input} >> [net = std::move(net), &input](const IP_Port &forwarder) {
|
||||
CONSUME1_OR_RETURN(const uint16_t sendback_length, input);
|
||||
CONSUME_OR_RETURN(const uint8_t *sendback, input, sendback_length);
|
||||
|
||||
forward_reply(net.get(), &forwarder, sendback, sendback_length, input.data, input.size);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
fuzz_select_target(data, size, TestSendForwardRequest, TestForwardReply);
|
||||
return 0;
|
||||
}
|
1025
external/toxcore/c-toxcore/toxcore/friend_connection.c
vendored
Normal file
1025
external/toxcore/c-toxcore/toxcore/friend_connection.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
176
external/toxcore/c-toxcore/toxcore/friend_connection.h
vendored
Normal file
176
external/toxcore/c-toxcore/toxcore/friend_connection.h
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Connection to friends.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_FRIEND_CONNECTION_H
|
||||
#define C_TOXCORE_TOXCORE_FRIEND_CONNECTION_H
|
||||
|
||||
#include "DHT.h"
|
||||
#include "LAN_discovery.h"
|
||||
#include "net_crypto.h"
|
||||
#include "onion_client.h"
|
||||
|
||||
#define MAX_FRIEND_CONNECTION_CALLBACKS 2
|
||||
#define MESSENGER_CALLBACK_INDEX 0
|
||||
#define GROUPCHAT_CALLBACK_INDEX 1
|
||||
|
||||
#define PACKET_ID_ALIVE 16
|
||||
#define PACKET_ID_SHARE_RELAYS 17
|
||||
#define PACKET_ID_FRIEND_REQUESTS 18
|
||||
|
||||
/** Interval between the sending of ping packets. */
|
||||
#define FRIEND_PING_INTERVAL 8
|
||||
|
||||
/** If no packets are received from friend in this time interval, kill the connection. */
|
||||
#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 4)
|
||||
|
||||
/** Time before friend is removed from the DHT after last hearing about him. */
|
||||
#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT
|
||||
|
||||
#define FRIEND_MAX_STORED_TCP_RELAYS (MAX_FRIEND_TCP_CONNECTIONS * 4)
|
||||
|
||||
/** Max number of tcp relays sent to friends */
|
||||
#define MAX_SHARED_RELAYS RECOMMENDED_FRIEND_TCP_CONNECTIONS
|
||||
|
||||
/** How often we share our TCP relays with each friend connection */
|
||||
#define SHARE_RELAYS_INTERVAL (60 * 2)
|
||||
|
||||
|
||||
typedef enum Friendconn_Status {
|
||||
FRIENDCONN_STATUS_NONE,
|
||||
FRIENDCONN_STATUS_CONNECTING,
|
||||
FRIENDCONN_STATUS_CONNECTED,
|
||||
} Friendconn_Status;
|
||||
|
||||
typedef struct Friend_Connections Friend_Connections;
|
||||
|
||||
non_null() Net_Crypto *friendconn_net_crypto(const Friend_Connections *fr_c);
|
||||
|
||||
/** @return friendcon_id corresponding to the real public key on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int getfriend_conn_id_pk(const Friend_Connections *fr_c, const uint8_t *real_pk);
|
||||
|
||||
/** @brief Increases lock_count for the connection with friendcon_id by 1.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int friend_connection_lock(const Friend_Connections *fr_c, int friendcon_id);
|
||||
|
||||
/**
|
||||
* @retval FRIENDCONN_STATUS_CONNECTED if the friend is connected.
|
||||
* @retval FRIENDCONN_STATUS_CONNECTING if the friend isn't connected.
|
||||
* @retval FRIENDCONN_STATUS_NONE on failure.
|
||||
*/
|
||||
non_null()
|
||||
unsigned int friend_con_connected(const Friend_Connections *fr_c, int friendcon_id);
|
||||
|
||||
/** @brief Copy public keys associated to friendcon_id.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(3) nullable(1, 2)
|
||||
int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, const Friend_Connections *fr_c, int friendcon_id);
|
||||
|
||||
/** Set temp dht key for connection. */
|
||||
non_null()
|
||||
void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata);
|
||||
|
||||
typedef int global_status_cb(void *object, int id, bool status, void *userdata);
|
||||
|
||||
typedef int fc_status_cb(void *object, int id, bool status, void *userdata);
|
||||
typedef int fc_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
|
||||
typedef int fc_lossy_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/** Set global status callback for friend connections. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_global_status_callback(Friend_Connections *fr_c, global_status_cb *global_status_callback, void *object);
|
||||
|
||||
/** @brief Set the callbacks for the friend connection.
|
||||
* @param index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we
|
||||
* want the callback to set in the array.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure
|
||||
*/
|
||||
non_null(1) nullable(4, 5, 6, 7)
|
||||
int friend_connection_callbacks(const Friend_Connections *fr_c, int friendcon_id, unsigned int index,
|
||||
fc_status_cb *status_callback,
|
||||
fc_data_cb *data_callback,
|
||||
fc_lossy_data_cb *lossy_data_callback,
|
||||
void *object, int number);
|
||||
|
||||
/** @brief return the crypt_connection_id for the connection.
|
||||
*
|
||||
* @return crypt_connection_id on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int friend_connection_crypt_connection_id(const Friend_Connections *fr_c, int friendcon_id);
|
||||
|
||||
/** @brief Create a new friend connection.
|
||||
* If one to that real public key already exists, increase lock count and return it.
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @return connection id on success.
|
||||
*/
|
||||
non_null()
|
||||
int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key);
|
||||
|
||||
/** @brief Kill a friend connection.
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id);
|
||||
|
||||
/** @brief Send a Friend request packet.
|
||||
*
|
||||
* @retval -1 if failure.
|
||||
* @retval 0 if it sent the friend request directly to the friend.
|
||||
* @return the number of peers it was routed through if it did not send it directly.
|
||||
*/
|
||||
non_null()
|
||||
int send_friend_request_packet(
|
||||
Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, uint16_t length);
|
||||
|
||||
typedef int fr_request_cb(
|
||||
void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t len, void *userdata);
|
||||
|
||||
/** @brief Set friend request callback.
|
||||
*
|
||||
* This function will be called every time a friend request packet is received.
|
||||
*/
|
||||
non_null()
|
||||
void set_friend_request_callback(Friend_Connections *fr_c, fr_request_cb *fr_request_callback, void *object);
|
||||
|
||||
/** Create new friend_connections instance. */
|
||||
non_null()
|
||||
Friend_Connections *new_friend_connections(
|
||||
const Logger *logger, const Mono_Time *mono_time, const Network *ns,
|
||||
Onion_Client *onion_c, bool local_discovery_enabled);
|
||||
|
||||
/** main friend_connections loop. */
|
||||
non_null()
|
||||
void do_friend_connections(Friend_Connections *fr_c, void *userdata);
|
||||
|
||||
/** Free everything related with friend_connections. */
|
||||
nullable(1)
|
||||
void kill_friend_connections(Friend_Connections *fr_c);
|
||||
|
||||
typedef struct Friend_Conn Friend_Conn;
|
||||
|
||||
non_null() Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id);
|
||||
non_null() int friend_conn_get_onion_friendnum(const Friend_Conn *fc);
|
||||
non_null() const IP_Port *friend_conn_get_dht_ip_port(const Friend_Conn *fc);
|
||||
|
||||
#endif
|
14
external/toxcore/c-toxcore/toxcore/friend_connection_test.cc
vendored
Normal file
14
external/toxcore/c-toxcore/toxcore/friend_connection_test.cc
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#include "friend_connection.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(Jfreegman) make this useful or remove it after NGC is merged
|
||||
TEST(friend_connection, NullTest)
|
||||
{
|
||||
(void)friend_conn_get_onion_friendnum;
|
||||
(void)friend_conn_get_dht_ip_port;
|
||||
}
|
||||
|
||||
} // namespace
|
171
external/toxcore/c-toxcore/toxcore/friend_requests.c
vendored
Normal file
171
external/toxcore/c-toxcore/toxcore/friend_requests.c
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle friend requests.
|
||||
*/
|
||||
#include "friend_requests.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccompat.h"
|
||||
#include "util.h"
|
||||
|
||||
/**
|
||||
* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem.
|
||||
* TODO(irungentoo): Make this better (This will most likely tie in with the way we will handle spam).
|
||||
*/
|
||||
#define MAX_RECEIVED_STORED 32
|
||||
|
||||
struct Received_Requests {
|
||||
uint8_t requests[MAX_RECEIVED_STORED][CRYPTO_PUBLIC_KEY_SIZE];
|
||||
uint16_t requests_index;
|
||||
};
|
||||
|
||||
struct Friend_Requests {
|
||||
uint32_t nospam;
|
||||
fr_friend_request_cb *handle_friendrequest;
|
||||
uint8_t handle_friendrequest_isset;
|
||||
void *handle_friendrequest_object;
|
||||
|
||||
filter_function_cb *filter_function;
|
||||
void *filter_function_userdata;
|
||||
|
||||
struct Received_Requests received;
|
||||
};
|
||||
|
||||
/** Set and get the nospam variable used to prevent one type of friend request spam. */
|
||||
void set_nospam(Friend_Requests *fr, uint32_t num)
|
||||
{
|
||||
fr->nospam = num;
|
||||
}
|
||||
|
||||
uint32_t get_nospam(const Friend_Requests *fr)
|
||||
{
|
||||
return fr->nospam;
|
||||
}
|
||||
|
||||
|
||||
/** Set the function that will be executed when a friend request for us is received. */
|
||||
void callback_friendrequest(Friend_Requests *fr, fr_friend_request_cb *function, void *object)
|
||||
{
|
||||
fr->handle_friendrequest = function;
|
||||
fr->handle_friendrequest_isset = 1;
|
||||
fr->handle_friendrequest_object = object;
|
||||
}
|
||||
|
||||
/** @brief Set the function used to check if a friend request should be displayed to the user or not.
|
||||
* It must return 0 if the request is ok (anything else if it is bad).
|
||||
*/
|
||||
void set_filter_function(Friend_Requests *fr, filter_function_cb *function, void *userdata)
|
||||
{
|
||||
fr->filter_function = function;
|
||||
fr->filter_function_userdata = userdata;
|
||||
}
|
||||
|
||||
/** Add to list of received friend requests. */
|
||||
non_null()
|
||||
static void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk)
|
||||
{
|
||||
if (fr->received.requests_index >= MAX_RECEIVED_STORED) {
|
||||
fr->received.requests_index = 0;
|
||||
}
|
||||
|
||||
pk_copy(fr->received.requests[fr->received.requests_index], real_pk);
|
||||
++fr->received.requests_index;
|
||||
}
|
||||
|
||||
/** @brief Check if a friend request was already received.
|
||||
*
|
||||
* @retval false if it did not.
|
||||
* @retval true if it did.
|
||||
*/
|
||||
non_null()
|
||||
static bool request_received(const Friend_Requests *fr, const uint8_t *real_pk)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_RECEIVED_STORED; ++i) {
|
||||
if (pk_equal(fr->received.requests[i], real_pk)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @brief Remove real_pk from received_requests list.
|
||||
*
|
||||
* @retval 0 if it removed it successfully.
|
||||
* @retval -1 if it didn't find it.
|
||||
*/
|
||||
int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_RECEIVED_STORED; ++i) {
|
||||
if (pk_equal(fr->received.requests[i], real_pk)) {
|
||||
crypto_memzero(fr->received.requests[i], CRYPTO_PUBLIC_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
non_null()
|
||||
static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
Friend_Requests *const fr = (Friend_Requests *)object;
|
||||
|
||||
if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
++packet;
|
||||
--length;
|
||||
|
||||
if (fr->handle_friendrequest_isset == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (request_received(fr, source_pubkey)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fr->filter_function != nullptr) {
|
||||
if (fr->filter_function(source_pubkey, fr->filter_function_userdata) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
addto_receivedlist(fr, source_pubkey);
|
||||
|
||||
const uint32_t message_len = length - sizeof(fr->nospam);
|
||||
VLA(uint8_t, message, message_len + 1);
|
||||
memcpy(message, packet + sizeof(fr->nospam), message_len);
|
||||
message[SIZEOF_VLA(message) - 1] = 0; /* Be sure the message is null terminated. */
|
||||
|
||||
fr->handle_friendrequest(fr->handle_friendrequest_object, source_pubkey, message, message_len, userdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c)
|
||||
{
|
||||
set_friend_request_callback(fr_c, &friendreq_handlepacket, fr);
|
||||
}
|
||||
|
||||
Friend_Requests *friendreq_new(void)
|
||||
{
|
||||
return (Friend_Requests *)calloc(1, sizeof(Friend_Requests));
|
||||
}
|
||||
|
||||
void friendreq_kill(Friend_Requests *fr)
|
||||
{
|
||||
free(fr);
|
||||
}
|
54
external/toxcore/c-toxcore/toxcore/friend_requests.h
vendored
Normal file
54
external/toxcore/c-toxcore/toxcore/friend_requests.h
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle friend requests.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_FRIEND_REQUESTS_H
|
||||
#define C_TOXCORE_TOXCORE_FRIEND_REQUESTS_H
|
||||
|
||||
#include "friend_connection.h"
|
||||
|
||||
#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t)))
|
||||
|
||||
typedef struct Friend_Requests Friend_Requests;
|
||||
|
||||
/** Set and get the nospam variable used to prevent one type of friend request spam. */
|
||||
non_null() void set_nospam(Friend_Requests *fr, uint32_t num);
|
||||
non_null() uint32_t get_nospam(const Friend_Requests *fr);
|
||||
|
||||
/** @brief Remove real_pk from received_requests list.
|
||||
*
|
||||
* @retval 0 if it removed it successfully.
|
||||
* @retval -1 if it didn't find it.
|
||||
*/
|
||||
non_null()
|
||||
int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk);
|
||||
|
||||
typedef void fr_friend_request_cb(void *object, const uint8_t *public_key, const uint8_t *message, size_t length,
|
||||
void *user_data);
|
||||
|
||||
/** Set the function that will be executed when a friend request for us is received. */
|
||||
non_null()
|
||||
void callback_friendrequest(Friend_Requests *fr, fr_friend_request_cb *function, void *object);
|
||||
|
||||
typedef int filter_function_cb(const uint8_t *public_key, void *user_data);
|
||||
|
||||
/** @brief Set the function used to check if a friend request should be displayed to the user or not.
|
||||
* It must return 0 if the request is ok (anything else if it is bad).
|
||||
*/
|
||||
non_null()
|
||||
void set_filter_function(Friend_Requests *fr, filter_function_cb *function, void *userdata);
|
||||
|
||||
/** Sets up friendreq packet handlers. */
|
||||
non_null()
|
||||
void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c);
|
||||
|
||||
Friend_Requests *friendreq_new(void);
|
||||
|
||||
nullable(1)
|
||||
void friendreq_kill(Friend_Requests *fr);
|
||||
|
||||
#endif
|
3867
external/toxcore/c-toxcore/toxcore/group.c
vendored
Normal file
3867
external/toxcore/c-toxcore/toxcore/group.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
398
external/toxcore/c-toxcore/toxcore/group.h
vendored
Normal file
398
external/toxcore/c-toxcore/toxcore/group.h
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Slightly better groupchats implementation.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_GROUP_H
|
||||
#define C_TOXCORE_TOXCORE_GROUP_H
|
||||
|
||||
#include "Messenger.h"
|
||||
|
||||
typedef enum Groupchat_Type {
|
||||
GROUPCHAT_TYPE_TEXT,
|
||||
GROUPCHAT_TYPE_AV,
|
||||
} Groupchat_Type;
|
||||
|
||||
typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t peer_number);
|
||||
typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object);
|
||||
typedef void group_on_delete_cb(void *object, uint32_t conference_number);
|
||||
|
||||
/** @brief Callback for group invites.
|
||||
*
|
||||
* data of length is what needs to be passed to `join_groupchat()`.
|
||||
*/
|
||||
typedef void g_conference_invite_cb(Messenger *m, uint32_t friend_number, int type, const uint8_t *cookie,
|
||||
size_t length, void *user_data);
|
||||
|
||||
/** Callback for group connection. */
|
||||
typedef void g_conference_connected_cb(Messenger *m, uint32_t conference_number, void *user_data);
|
||||
|
||||
/** Callback for group messages. */
|
||||
typedef void g_conference_message_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, int type,
|
||||
const uint8_t *message, size_t length, void *user_data);
|
||||
|
||||
/** Callback for peer nickname changes. */
|
||||
typedef void peer_name_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, const uint8_t *name,
|
||||
size_t length, void *user_data);
|
||||
|
||||
/** Set callback function for peer list changes. */
|
||||
typedef void peer_list_changed_cb(Messenger *m, uint32_t conference_number, void *user_data);
|
||||
|
||||
/** @brief Callback for title changes.
|
||||
*
|
||||
* If peer_number == -1, then author is unknown (e.g. initial joining the group).
|
||||
*/
|
||||
typedef void title_cb(Messenger *m, uint32_t conference_number, uint32_t peer_number, const uint8_t *title,
|
||||
size_t length, void *user_data);
|
||||
|
||||
/** @brief Callback for lossy packets.
|
||||
*
|
||||
* NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed.
|
||||
*/
|
||||
typedef int lossy_packet_cb(void *object, uint32_t conference_number, uint32_t peer_number, void *peer_object,
|
||||
const uint8_t *packet, uint16_t length);
|
||||
|
||||
typedef struct Group_Chats Group_Chats;
|
||||
|
||||
non_null()
|
||||
const Mono_Time *g_mono_time(const Group_Chats *g_c);
|
||||
|
||||
/** Set the callback for group invites. */
|
||||
non_null()
|
||||
void g_callback_group_invite(Group_Chats *g_c, g_conference_invite_cb *function);
|
||||
|
||||
/** Set the callback for group connection. */
|
||||
non_null()
|
||||
void g_callback_group_connected(Group_Chats *g_c, g_conference_connected_cb *function);
|
||||
|
||||
/** Set the callback for group messages. */
|
||||
non_null()
|
||||
void g_callback_group_message(Group_Chats *g_c, g_conference_message_cb *function);
|
||||
|
||||
|
||||
/** Set callback function for title changes. */
|
||||
non_null()
|
||||
void g_callback_group_title(Group_Chats *g_c, title_cb *function);
|
||||
|
||||
/** @brief Set callback function for peer nickname changes.
|
||||
*
|
||||
* It gets called every time a peer changes their nickname.
|
||||
*/
|
||||
non_null()
|
||||
void g_callback_peer_name(Group_Chats *g_c, peer_name_cb *function);
|
||||
|
||||
/** @brief Set callback function for peer list changes.
|
||||
*
|
||||
* It gets called every time the name list changes(new peer, deleted peer)
|
||||
*/
|
||||
non_null()
|
||||
void g_callback_peer_list_changed(Group_Chats *g_c, peer_list_changed_cb *function);
|
||||
|
||||
/** @brief Creates a new groupchat and puts it in the chats array.
|
||||
*
|
||||
* @param rng Random number generator used for generating the group ID.
|
||||
* @param type is one of `GROUPCHAT_TYPE_*`
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_groupchat(Group_Chats *g_c, const Random *rng, uint8_t type);
|
||||
|
||||
/** @brief Delete a groupchat from the chats array, informing the group first as
|
||||
* appropriate.
|
||||
*
|
||||
* @retval true on success.
|
||||
* @retval false if groupnumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
bool del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently);
|
||||
|
||||
/**
|
||||
* @brief Copy the public key of (frozen, if frozen is true) peernumber who is in
|
||||
* groupnumber to pk.
|
||||
*
|
||||
* @param pk must be CRYPTO_PUBLIC_KEY_SIZE long.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if peernumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *pk, bool frozen);
|
||||
|
||||
/**
|
||||
* @brief Return the size of (frozen, if frozen is true) peernumber's name.
|
||||
*
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if peernumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, bool frozen);
|
||||
|
||||
/**
|
||||
* @brief Copy the name of (frozen, if frozen is true) peernumber who is in
|
||||
* groupnumber to name.
|
||||
*
|
||||
* @param name must be at least MAX_NAME_LENGTH long.
|
||||
*
|
||||
* @return length of name if success
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if peernumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_peername(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *name,
|
||||
bool frozen);
|
||||
|
||||
/**
|
||||
* @brief Copy last active timestamp of frozen peernumber who is in groupnumber to
|
||||
* last_active.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if peernumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_frozen_last_active(
|
||||
const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint64_t *last_active);
|
||||
|
||||
/** @brief Set maximum number of frozen peers.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen);
|
||||
|
||||
/** @brief invite friendnumber to groupnumber.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if invite packet failed to send.
|
||||
* @retval -3 if we are not connected to the group chat.
|
||||
*/
|
||||
non_null()
|
||||
int invite_friend(const Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber);
|
||||
|
||||
/** @brief Join a group (we need to have been invited first).
|
||||
*
|
||||
* @param expected_type is the groupchat type we expect the chat we are joining
|
||||
* to have.
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 if data length is invalid.
|
||||
* @retval -2 if group is not the expected type.
|
||||
* @retval -3 if friendnumber is invalid.
|
||||
* @retval -4 if client is already in this group.
|
||||
* @retval -5 if group instance failed to initialize.
|
||||
* @retval -6 if join packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int join_groupchat(
|
||||
Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief send a group message
|
||||
* @retval 0 on success
|
||||
* @see send_message_group for error codes.
|
||||
*/
|
||||
non_null()
|
||||
int group_message_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *message, uint16_t length);
|
||||
|
||||
/** @brief send a group action
|
||||
* @retval 0 on success
|
||||
* @see send_message_group for error codes.
|
||||
*/
|
||||
non_null()
|
||||
int group_action_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *action, uint16_t length);
|
||||
|
||||
/** @brief set the group's title, limited to MAX_NAME_LENGTH.
|
||||
* @retval 0 on success
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if title is too long or empty.
|
||||
* @retval -3 if packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int group_title_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *title, uint8_t title_len);
|
||||
|
||||
|
||||
/** @brief return the group's title size.
|
||||
* @retval -1 of groupnumber is invalid.
|
||||
* @retval -2 if title is too long or empty.
|
||||
*/
|
||||
non_null()
|
||||
int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
/** @brief Get group title from groupnumber and put it in title.
|
||||
*
|
||||
* Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
|
||||
*
|
||||
* @return length of copied title if success.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if title is too long or empty.
|
||||
*/
|
||||
non_null()
|
||||
int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title);
|
||||
|
||||
/**
|
||||
* @return the number of (frozen, if frozen is true) peers in the group chat on success.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
*/
|
||||
non_null()
|
||||
int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen);
|
||||
|
||||
/**
|
||||
* @retval 1 if the peernumber corresponds to ours.
|
||||
* @retval 0 if the peernumber is not ours.
|
||||
* @retval -1 if groupnumber is invalid.
|
||||
* @retval -2 if peernumber is invalid.
|
||||
* @retval -3 if we are not connected to the group chat.
|
||||
*/
|
||||
non_null()
|
||||
int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
|
||||
|
||||
/** Set handlers for custom lossy packets. */
|
||||
non_null()
|
||||
void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, lossy_packet_cb *function);
|
||||
|
||||
/** @brief High level function to send custom lossy packets.
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int send_group_lossy_packet(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Return the number of chats in the instance m.
|
||||
*
|
||||
* You should use this to determine how much memory to allocate
|
||||
* for copy_chatlist.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t count_chatlist(const Group_Chats *g_c);
|
||||
|
||||
/** @brief Copy a list of valid chat IDs into the array out_list.
|
||||
*
|
||||
* If out_list is NULL, returns 0.
|
||||
* Otherwise, returns the number of elements copied.
|
||||
* If the array was too small, the contents
|
||||
* of out_list will be truncated to list_size.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t copy_chatlist(const Group_Chats *g_c, uint32_t *out_list, uint32_t list_size);
|
||||
|
||||
/** @brief return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is.
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @return type on success.
|
||||
*/
|
||||
non_null()
|
||||
int group_get_type(const Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
/** @brief Copies the unique id of `group_chat[groupnumber]` into `id`.
|
||||
*
|
||||
* @retval false on failure.
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool conference_get_id(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *id);
|
||||
|
||||
non_null() int32_t conference_by_id(const Group_Chats *g_c, const uint8_t *id);
|
||||
|
||||
/** Send current name (set in messenger) to all online groups. */
|
||||
non_null()
|
||||
void send_name_all_groups(const Group_Chats *g_c);
|
||||
|
||||
/** @brief Set the object that is tied to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
int group_set_object(const Group_Chats *g_c, uint32_t groupnumber, void *object);
|
||||
|
||||
/** @brief Set the object that is tied to the group peer.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure
|
||||
*/
|
||||
non_null(1) nullable(4)
|
||||
int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, void *object);
|
||||
|
||||
/** @brief Return the object tied to the group chat previously set by group_set_object.
|
||||
*
|
||||
* @retval NULL on failure.
|
||||
* @return object on success.
|
||||
*/
|
||||
non_null()
|
||||
void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
/** @brief Return the object tied to the group chat peer previously set by group_peer_set_object.
|
||||
*
|
||||
* @retval NULL on failure.
|
||||
* @return object on success.
|
||||
*/
|
||||
non_null()
|
||||
void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
|
||||
|
||||
/** @brief Set a function to be called when a new peer joins a group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
int callback_groupchat_peer_new(const Group_Chats *g_c, uint32_t groupnumber, peer_on_join_cb *function);
|
||||
|
||||
/** @brief Set a function to be called when a peer leaves a group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
int callback_groupchat_peer_delete(const Group_Chats *g_c, uint32_t groupnumber, peer_on_leave_cb *function);
|
||||
|
||||
/** @brief Set a function to be called when the group chat is deleted.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
int callback_groupchat_delete(const Group_Chats *g_c, uint32_t groupnumber, group_on_delete_cb *function);
|
||||
|
||||
/** Return size of the conferences data (for saving). */
|
||||
non_null()
|
||||
uint32_t conferences_size(const Group_Chats *g_c);
|
||||
|
||||
/** Save the conferences in data (must be allocated memory of size at least `conferences_size()`). */
|
||||
non_null()
|
||||
uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data);
|
||||
|
||||
/**
|
||||
* Load a state section.
|
||||
*
|
||||
* @param data Data to load
|
||||
* @param length Length of data
|
||||
* @param type Type of section (`STATE_TYPE_*`)
|
||||
* @param status Result of loading section is stored here if the section is handled.
|
||||
* @return true iff section handled.
|
||||
*/
|
||||
non_null()
|
||||
bool conferences_load_state_section(
|
||||
Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type, State_Load_Status *status);
|
||||
|
||||
/** Create new groupchat instance. */
|
||||
non_null()
|
||||
Group_Chats *new_groupchats(const Mono_Time *mono_time, Messenger *m);
|
||||
|
||||
/** main groupchats loop. */
|
||||
non_null(1) nullable(2)
|
||||
void do_groupchats(Group_Chats *g_c, void *userdata);
|
||||
|
||||
/** Free everything related with group chats. */
|
||||
nullable(1)
|
||||
void kill_groupchats(Group_Chats *g_c);
|
||||
|
||||
#endif
|
462
external/toxcore/c-toxcore/toxcore/group_announce.c
vendored
Normal file
462
external/toxcore/c-toxcore/toxcore/group_announce.c
vendored
Normal file
@ -0,0 +1,462 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
#include "group_announce.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LAN_discovery.h"
|
||||
#include "ccompat.h"
|
||||
#include "mono_time.h"
|
||||
#include "util.h"
|
||||
|
||||
/**
|
||||
* Removes `announces` from `gc_announces_list`.
|
||||
*/
|
||||
non_null()
|
||||
static void remove_announces(GC_Announces_List *gc_announces_list, GC_Announces *announces)
|
||||
{
|
||||
if (announces == nullptr || gc_announces_list == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (announces->prev_announce != nullptr) {
|
||||
announces->prev_announce->next_announce = announces->next_announce;
|
||||
} else {
|
||||
gc_announces_list->root_announces = announces->next_announce;
|
||||
}
|
||||
|
||||
if (announces->next_announce != nullptr) {
|
||||
announces->next_announce->prev_announce = announces->prev_announce;
|
||||
}
|
||||
|
||||
free(announces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the announce designated by `chat_id`.
|
||||
* Returns null if no announce is found.
|
||||
*/
|
||||
non_null()
|
||||
static GC_Announces *get_announces_by_chat_id(const GC_Announces_List *gc_announces_list, const uint8_t *chat_id)
|
||||
{
|
||||
GC_Announces *announces = gc_announces_list->root_announces;
|
||||
|
||||
while (announces != nullptr) {
|
||||
if (memcmp(announces->chat_id, chat_id, CHAT_ID_SIZE) == 0) {
|
||||
return announces;
|
||||
}
|
||||
|
||||
announces = announces->next_announce;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int gca_get_announces(const GC_Announces_List *gc_announces_list, GC_Announce *gc_announces, uint8_t max_nodes,
|
||||
const uint8_t *chat_id, const uint8_t *except_public_key)
|
||||
{
|
||||
if (gc_announces == nullptr || gc_announces_list == nullptr || chat_id == nullptr || max_nodes == 0
|
||||
|| except_public_key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const GC_Announces *announces = get_announces_by_chat_id(gc_announces_list, chat_id);
|
||||
|
||||
if (announces == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t added_count = 0;
|
||||
|
||||
for (size_t i = 0; i < announces->index && i < GCA_MAX_SAVED_ANNOUNCES_PER_GC && added_count < max_nodes; ++i) {
|
||||
const size_t index = i % GCA_MAX_SAVED_ANNOUNCES_PER_GC;
|
||||
|
||||
if (memcmp(except_public_key, &announces->peer_announces[index].base_announce.peer_public_key,
|
||||
ENC_PUBLIC_KEY_SIZE) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool already_added = false;
|
||||
|
||||
for (size_t j = 0; j < added_count; ++j) {
|
||||
if (memcmp(&gc_announces[j].peer_public_key, &announces->peer_announces[index].base_announce.peer_public_key,
|
||||
ENC_PUBLIC_KEY_SIZE) == 0) {
|
||||
already_added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_added) {
|
||||
gc_announces[added_count] = announces->peer_announces[index].base_announce;
|
||||
++added_count;
|
||||
}
|
||||
}
|
||||
|
||||
return added_count;
|
||||
}
|
||||
|
||||
uint16_t gca_pack_announces_list_size(uint16_t count)
|
||||
{
|
||||
return count * GCA_ANNOUNCE_MAX_SIZE;
|
||||
}
|
||||
|
||||
int gca_pack_announce(const Logger *log, uint8_t *data, uint16_t length, const GC_Announce *announce)
|
||||
{
|
||||
if (length < GCA_ANNOUNCE_MAX_SIZE) {
|
||||
LOGGER_ERROR(log, "Invalid announce length: %u", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data == nullptr) {
|
||||
LOGGER_ERROR(log, "data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announce == nullptr) {
|
||||
LOGGER_ERROR(log, "announce is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
memcpy(data + offset, announce->peer_public_key, ENC_PUBLIC_KEY_SIZE);
|
||||
offset += ENC_PUBLIC_KEY_SIZE;
|
||||
|
||||
data[offset] = announce->ip_port_is_set ? 1 : 0;
|
||||
++offset;
|
||||
|
||||
data[offset] = announce->tcp_relays_count;
|
||||
++offset;
|
||||
|
||||
if (!announce->ip_port_is_set && announce->tcp_relays_count == 0) {
|
||||
LOGGER_ERROR(log, "Failed to pack announce: no valid ip_port or tcp relay");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announce->ip_port_is_set) {
|
||||
const int ip_port_length = pack_ip_port(log, data + offset, length - offset, &announce->ip_port);
|
||||
|
||||
if (ip_port_length == -1) {
|
||||
LOGGER_ERROR(log, "Failed to pack ip_port");
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset += ip_port_length;
|
||||
}
|
||||
|
||||
const int nodes_length = pack_nodes(log, data + offset, length - offset, announce->tcp_relays,
|
||||
announce->tcp_relays_count);
|
||||
|
||||
if (nodes_length == -1) {
|
||||
LOGGER_ERROR(log, "Failed to pack TCP nodes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nodes_length + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks `announce` into `data` buffer of size `length`.
|
||||
*
|
||||
* Returns the size of the unpacked data on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
static int gca_unpack_announce(const Logger *log, const uint8_t *data, uint16_t length, GC_Announce *announce)
|
||||
{
|
||||
if (length < ENC_PUBLIC_KEY_SIZE + 2) {
|
||||
LOGGER_ERROR(log, "Invalid announce length: %u", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data == nullptr) {
|
||||
LOGGER_ERROR(log, "data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announce == nullptr) {
|
||||
LOGGER_ERROR(log, "announce is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
memcpy(announce->peer_public_key, data + offset, ENC_PUBLIC_KEY_SIZE);
|
||||
offset += ENC_PUBLIC_KEY_SIZE;
|
||||
|
||||
net_unpack_bool(&data[offset], &announce->ip_port_is_set);
|
||||
++offset;
|
||||
|
||||
announce->tcp_relays_count = data[offset];
|
||||
++offset;
|
||||
|
||||
if (announce->tcp_relays_count > GCA_MAX_ANNOUNCED_TCP_RELAYS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announce->ip_port_is_set) {
|
||||
if (length - offset == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int ip_port_length = unpack_ip_port(&announce->ip_port, data + offset, length - offset, false);
|
||||
|
||||
if (ip_port_length == -1) {
|
||||
LOGGER_ERROR(log, "Failed to unpack ip_port");
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset += ip_port_length;
|
||||
}
|
||||
|
||||
uint16_t nodes_length;
|
||||
const int nodes_count = unpack_nodes(announce->tcp_relays, announce->tcp_relays_count, &nodes_length,
|
||||
data + offset, length - offset, true);
|
||||
|
||||
if (nodes_count != announce->tcp_relays_count) {
|
||||
LOGGER_ERROR(log, "Failed to unpack TCP nodes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return offset + nodes_length;
|
||||
}
|
||||
|
||||
int gca_pack_public_announce(const Logger *log, uint8_t *data, uint16_t length,
|
||||
const GC_Public_Announce *public_announce)
|
||||
{
|
||||
if (public_announce == nullptr || data == nullptr || length < CHAT_ID_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(data, public_announce->chat_public_key, CHAT_ID_SIZE);
|
||||
|
||||
const int packed_size = gca_pack_announce(log, data + CHAT_ID_SIZE, length - CHAT_ID_SIZE,
|
||||
&public_announce->base_announce);
|
||||
|
||||
if (packed_size < 0) {
|
||||
LOGGER_ERROR(log, "Failed to pack public group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return packed_size + CHAT_ID_SIZE;
|
||||
}
|
||||
|
||||
int gca_unpack_public_announce(const Logger *log, const uint8_t *data, uint16_t length,
|
||||
GC_Public_Announce *public_announce)
|
||||
{
|
||||
if (length < CHAT_ID_SIZE) {
|
||||
LOGGER_ERROR(log, "invalid public announce length: %u", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data == nullptr) {
|
||||
LOGGER_ERROR(log, "data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (public_announce == nullptr) {
|
||||
LOGGER_ERROR(log, "public_announce is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(public_announce->chat_public_key, data, CHAT_ID_SIZE);
|
||||
|
||||
const int base_announce_size = gca_unpack_announce(log, data + ENC_PUBLIC_KEY_SIZE, length - ENC_PUBLIC_KEY_SIZE,
|
||||
&public_announce->base_announce);
|
||||
|
||||
if (base_announce_size == -1) {
|
||||
LOGGER_ERROR(log, "Failed to unpack group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return base_announce_size + CHAT_ID_SIZE;
|
||||
}
|
||||
|
||||
int gca_pack_announces_list(const Logger *log, uint8_t *data, uint16_t length, const GC_Announce *announces,
|
||||
uint8_t announces_count, size_t *processed)
|
||||
{
|
||||
if (data == nullptr) {
|
||||
LOGGER_ERROR(log, "data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announces == nullptr) {
|
||||
LOGGER_ERROR(log, "announces is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
|
||||
for (size_t i = 0; i < announces_count; ++i) {
|
||||
const int packed_length = gca_pack_announce(log, data + offset, length - offset, &announces[i]);
|
||||
|
||||
if (packed_length < 0) {
|
||||
LOGGER_ERROR(log, "Failed to pack group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset += packed_length;
|
||||
}
|
||||
|
||||
if (processed != nullptr) {
|
||||
*processed = offset;
|
||||
}
|
||||
|
||||
return announces_count;
|
||||
}
|
||||
|
||||
int gca_unpack_announces_list(const Logger *log, const uint8_t *data, uint16_t length, GC_Announce *announces,
|
||||
uint8_t max_count)
|
||||
{
|
||||
if (data == nullptr) {
|
||||
LOGGER_ERROR(log, "data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announces == nullptr) {
|
||||
LOGGER_ERROR(log, "announces is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t offset = 0;
|
||||
int announces_count = 0;
|
||||
|
||||
for (size_t i = 0; i < max_count && length > offset; ++i) {
|
||||
const int unpacked_length = gca_unpack_announce(log, data + offset, length - offset, &announces[i]);
|
||||
|
||||
if (unpacked_length == -1) {
|
||||
LOGGER_WARNING(log, "Failed to unpack group announce: %d %d", length, offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset += unpacked_length;
|
||||
++announces_count;
|
||||
}
|
||||
|
||||
return announces_count;
|
||||
}
|
||||
|
||||
GC_Peer_Announce *gca_add_announce(const Mono_Time *mono_time, GC_Announces_List *gc_announces_list,
|
||||
const GC_Public_Announce *public_announce)
|
||||
{
|
||||
if (gc_announces_list == nullptr || public_announce == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GC_Announces *announces = get_announces_by_chat_id(gc_announces_list, public_announce->chat_public_key);
|
||||
|
||||
// No entry for this chat_id exists so we create one
|
||||
if (announces == nullptr) {
|
||||
announces = (GC_Announces *)calloc(1, sizeof(GC_Announces));
|
||||
|
||||
if (announces == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
announces->index = 0;
|
||||
announces->prev_announce = nullptr;
|
||||
|
||||
if (gc_announces_list->root_announces != nullptr) {
|
||||
gc_announces_list->root_announces->prev_announce = announces;
|
||||
}
|
||||
|
||||
announces->next_announce = gc_announces_list->root_announces;
|
||||
gc_announces_list->root_announces = announces;
|
||||
memcpy(announces->chat_id, public_announce->chat_public_key, CHAT_ID_SIZE);
|
||||
}
|
||||
|
||||
const uint64_t cur_time = mono_time_get(mono_time);
|
||||
|
||||
announces->last_announce_received_timestamp = cur_time;
|
||||
|
||||
const uint64_t index = announces->index % GCA_MAX_SAVED_ANNOUNCES_PER_GC;
|
||||
|
||||
GC_Peer_Announce *gc_peer_announce = &announces->peer_announces[index];
|
||||
|
||||
gc_peer_announce->base_announce = public_announce->base_announce;
|
||||
|
||||
gc_peer_announce->timestamp = cur_time;
|
||||
|
||||
++announces->index;
|
||||
|
||||
return gc_peer_announce;
|
||||
}
|
||||
|
||||
bool gca_is_valid_announce(const GC_Announce *announce)
|
||||
{
|
||||
if (announce == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return announce->tcp_relays_count > 0 || announce->ip_port_is_set;
|
||||
}
|
||||
|
||||
GC_Announces_List *new_gca_list(void)
|
||||
{
|
||||
GC_Announces_List *announces_list = (GC_Announces_List *)calloc(1, sizeof(GC_Announces_List));
|
||||
return announces_list;
|
||||
}
|
||||
|
||||
void kill_gca(GC_Announces_List *announces_list)
|
||||
{
|
||||
if (announces_list == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
GC_Announces *root = announces_list->root_announces;
|
||||
|
||||
while (root != nullptr) {
|
||||
GC_Announces *next = root->next_announce;
|
||||
free(root);
|
||||
root = next;
|
||||
}
|
||||
|
||||
free(announces_list);
|
||||
}
|
||||
|
||||
/* How long we save a peer's announce before we consider it stale and remove it. */
|
||||
#define GCA_ANNOUNCE_SAVE_TIMEOUT 30
|
||||
|
||||
/* How often we run do_gca() */
|
||||
#define GCA_DO_GCA_TIMEOUT 1
|
||||
|
||||
void do_gca(const Mono_Time *mono_time, GC_Announces_List *gc_announces_list)
|
||||
{
|
||||
if (gc_announces_list == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mono_time_is_timeout(mono_time, gc_announces_list->last_timeout_check, GCA_DO_GCA_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gc_announces_list->last_timeout_check = mono_time_get(mono_time);
|
||||
|
||||
GC_Announces *announces = gc_announces_list->root_announces;
|
||||
|
||||
while (announces != nullptr) {
|
||||
if (mono_time_is_timeout(mono_time, announces->last_announce_received_timestamp, GCA_ANNOUNCE_SAVE_TIMEOUT)) {
|
||||
GC_Announces *to_delete = announces;
|
||||
announces = announces->next_announce;
|
||||
remove_announces(gc_announces_list, to_delete);
|
||||
continue;
|
||||
}
|
||||
|
||||
announces = announces->next_announce;
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_gca(GC_Announces_List *gc_announces_list, const uint8_t *chat_id)
|
||||
{
|
||||
if (gc_announces_list == nullptr || chat_id == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
GC_Announces *announces = get_announces_by_chat_id(gc_announces_list, chat_id);
|
||||
|
||||
if (announces != nullptr) {
|
||||
remove_announces(gc_announces_list, announces);
|
||||
}
|
||||
}
|
218
external/toxcore/c-toxcore/toxcore/group_announce.h
vendored
Normal file
218
external/toxcore/c-toxcore/toxcore/group_announce.h
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Similar to ping.h, but designed for group chat purposes
|
||||
*/
|
||||
#ifndef GROUP_ANNOUNCE_H
|
||||
#define GROUP_ANNOUNCE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "DHT.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The maximum number of announces to save for a particular group chat. */
|
||||
#define GCA_MAX_SAVED_ANNOUNCES_PER_GC 16
|
||||
|
||||
/* Maximum number of TCP relays that can be in an announce. */
|
||||
#define GCA_MAX_ANNOUNCED_TCP_RELAYS 1
|
||||
|
||||
/* Maximum number of announces we can send in an announce response. */
|
||||
#define GCA_MAX_SENT_ANNOUNCES 4
|
||||
|
||||
/* Maximum size of an announce. */
|
||||
#define GCA_ANNOUNCE_MAX_SIZE (ENC_PUBLIC_KEY_SIZE + 1 + 1 + (PACKED_NODE_SIZE_IP6 * 2))
|
||||
|
||||
/* Maximum size of a public announce. */
|
||||
#define GCA_PUBLIC_ANNOUNCE_MAX_SIZE (ENC_PUBLIC_KEY_SIZE + GCA_ANNOUNCE_MAX_SIZE)
|
||||
|
||||
typedef struct GC_Announce GC_Announce;
|
||||
typedef struct GC_Peer_Announce GC_Peer_Announce;
|
||||
typedef struct GC_Announces GC_Announces;
|
||||
typedef struct GC_Announces_List GC_Announces_List;
|
||||
typedef struct GC_Public_Announce GC_Public_Announce;
|
||||
|
||||
/* Base announce. */
|
||||
struct GC_Announce {
|
||||
Node_format tcp_relays[GCA_MAX_ANNOUNCED_TCP_RELAYS];
|
||||
uint8_t tcp_relays_count;
|
||||
bool ip_port_is_set;
|
||||
IP_Port ip_port;
|
||||
uint8_t peer_public_key[ENC_PUBLIC_KEY_SIZE];
|
||||
};
|
||||
|
||||
/* Peer announce for specific group. */
|
||||
struct GC_Peer_Announce {
|
||||
GC_Announce base_announce;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
/* Used for announces in public groups. */
|
||||
struct GC_Public_Announce {
|
||||
GC_Announce base_announce;
|
||||
uint8_t chat_public_key[ENC_PUBLIC_KEY_SIZE];
|
||||
};
|
||||
|
||||
/* A linked list that holds all announces for a particular group. */
|
||||
struct GC_Announces {
|
||||
uint8_t chat_id[CHAT_ID_SIZE];
|
||||
uint64_t index;
|
||||
uint64_t last_announce_received_timestamp;
|
||||
|
||||
GC_Peer_Announce peer_announces[GCA_MAX_SAVED_ANNOUNCES_PER_GC];
|
||||
|
||||
GC_Announces *next_announce;
|
||||
GC_Announces *prev_announce;
|
||||
};
|
||||
|
||||
/* A list of all announces. */
|
||||
struct GC_Announces_List {
|
||||
GC_Announces *root_announces;
|
||||
uint64_t last_timeout_check;
|
||||
};
|
||||
|
||||
|
||||
/** @brief Returns a new group announces list.
|
||||
*
|
||||
* The caller is responsible for freeing the memory with `kill_gca`.
|
||||
*/
|
||||
GC_Announces_List *new_gca_list(void);
|
||||
|
||||
/** @brief Frees all dynamically allocated memory associated with `announces_list`. */
|
||||
nullable(1)
|
||||
void kill_gca(GC_Announces_List *announces_list);
|
||||
|
||||
/** @brief Iterates through the announces list and removes announces that are considered stale.
|
||||
*
|
||||
* @param gc_announces_list The list of announces to iterate.
|
||||
*
|
||||
* This function should be called from the main loop, and will iterate the list a
|
||||
* maxmimum of once per second.
|
||||
*/
|
||||
non_null()
|
||||
void do_gca(const Mono_Time *mono_time, GC_Announces_List *gc_announces_list);
|
||||
|
||||
/** @brief Frees all dynamically allocated memory associated with an announces list entry.
|
||||
*
|
||||
* @param gc_announces_list The announces list we want to search through.
|
||||
* @param chat_id The chat ID that designates the entry we want to remove.
|
||||
*/
|
||||
non_null()
|
||||
void cleanup_gca(GC_Announces_List *gc_announces_list, const uint8_t *chat_id);
|
||||
|
||||
/** @brief Puts a set of announces from the announces list in supplied list.
|
||||
*
|
||||
* @param gc_announces_list The announces list we want to search for entries in.
|
||||
* @param gc_announces An empty announces list that will be filled with matches.
|
||||
* @param max_nodes The maximum number of matches that we want to add to the list.
|
||||
* @param chat_id The chat ID associated with the announces that we want to add.
|
||||
* @param except_public_key The public key associated with announces that we want to ignore.
|
||||
*
|
||||
* @return the number of added nodes on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gca_get_announces(const GC_Announces_List *gc_announces_list, GC_Announce *gc_announces, uint8_t max_nodes,
|
||||
const uint8_t *chat_id, const uint8_t *except_public_key);
|
||||
|
||||
/** @brief Adds a public_announce to list of announces.
|
||||
*
|
||||
* @param gc_announces_list The announces list that we want to add an entry to.
|
||||
* @param public_announce The public announce that we want to add.
|
||||
*
|
||||
* @return the peer announce on success.
|
||||
* @retval null on failure.
|
||||
*/
|
||||
non_null()
|
||||
GC_Peer_Announce *gca_add_announce(const Mono_Time *mono_time, GC_Announces_List *gc_announces_list,
|
||||
const GC_Public_Announce *public_announce);
|
||||
|
||||
/** @brief Packs an announce into a data buffer.
|
||||
*
|
||||
* @param data The data buffer being packed.
|
||||
* @param length The size in bytes of the data buffer. Must be at least GCA_ANNOUNCE_MAX_SIZE.
|
||||
* @param announce The announce being packed into the data buffer.
|
||||
*
|
||||
* @return the size of the packed data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gca_pack_announce(const Logger *log, uint8_t *data, uint16_t length, const GC_Announce *announce);
|
||||
|
||||
/** @brief Returns the number of bytes needed for a buff in which to pack `count` announces. */
|
||||
uint16_t gca_pack_announces_list_size(uint16_t count);
|
||||
|
||||
/** @brief Packs a list of announces into a data buffer.
|
||||
*
|
||||
* @param data The data buffer being packed.
|
||||
* @param length The size in bytes of the data buffer. Use gca_pack_announces_list_size to get the
|
||||
* required length.
|
||||
* @param announces The announces to be packed into the data buffer.
|
||||
* @param announces_count The number of announces in the announces list.
|
||||
* @param processed If non-null, will contain the number of bytes packed (only on success).
|
||||
*
|
||||
* @return the number of packed announces on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1, 2, 4) nullable(6)
|
||||
int gca_pack_announces_list(const Logger *log, uint8_t *data, uint16_t length, const GC_Announce *announces,
|
||||
uint8_t announces_count, size_t *processed);
|
||||
|
||||
/** @brief Unpacks packed announces from a data buffer into a supplied list.
|
||||
*
|
||||
* @param data The data buffer to unpack from.
|
||||
* @param length The size of the data buffer.
|
||||
* @param announces The announces list that the data buffer will be unpacked to.
|
||||
* @param max_count The maximum number of announces to unpack.
|
||||
*
|
||||
* @return the number of unpacked announces on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gca_unpack_announces_list(const Logger *log, const uint8_t *data, uint16_t length, GC_Announce *announces,
|
||||
uint8_t max_count);
|
||||
|
||||
/** @brief Packs a public announce into a data buffer.
|
||||
*
|
||||
* @param data The data buffer being packed.
|
||||
* @param length The size in bytes of the data buffer. Must be at least GCA_PUBLIC_ANNOUNCE_MAX_SIZE.
|
||||
* @param public_announce The public announce being packed into the data buffer.
|
||||
*
|
||||
* @return the size of the packed data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gca_pack_public_announce(const Logger *log, uint8_t *data, uint16_t length,
|
||||
const GC_Public_Announce *public_announce);
|
||||
|
||||
/** @brief Unpacks a public announce from a data buffer into a supplied public announce.
|
||||
*
|
||||
* @param data The data buffer to unpack from.
|
||||
* @param length The size of the data buffer.
|
||||
* @param public_announce The public announce to unpack the data buffer into.
|
||||
*
|
||||
* @return the size of the unpacked data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gca_unpack_public_announce(const Logger *log, const uint8_t *data, uint16_t length,
|
||||
GC_Public_Announce *public_announce);
|
||||
|
||||
/** @brief Returns true if the announce is valid.
|
||||
*
|
||||
* An announce is considered valid if there is at least one TCP relay, or the ip_port is set.
|
||||
*/
|
||||
non_null()
|
||||
bool gca_is_valid_announce(const GC_Announce *announce);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // GROUP_ANNOUNCE_H
|
106
external/toxcore/c-toxcore/toxcore/group_announce_fuzz_test.cc
vendored
Normal file
106
external/toxcore/c-toxcore/toxcore/group_announce_fuzz_test.cc
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
#include "group_announce.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../testing/fuzzing/fuzz_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TestUnpackAnnouncesList(Fuzz_Data &input)
|
||||
{
|
||||
CONSUME1_OR_RETURN(const uint8_t max_count, input);
|
||||
std::vector<GC_Announce> announces(max_count);
|
||||
|
||||
// TODO(iphydf): How do we know the packed size?
|
||||
CONSUME1_OR_RETURN(const uint16_t packed_size, input);
|
||||
|
||||
Logger *logger = logger_new();
|
||||
if (gca_unpack_announces_list(logger, input.data, input.size, announces.data(), max_count)
|
||||
!= -1) {
|
||||
std::vector<uint8_t> packed(packed_size);
|
||||
size_t processed;
|
||||
gca_pack_announces_list(
|
||||
logger, packed.data(), packed.size(), announces.data(), announces.size(), &processed);
|
||||
}
|
||||
logger_kill(logger);
|
||||
}
|
||||
|
||||
void TestUnpackPublicAnnounce(Fuzz_Data &input)
|
||||
{
|
||||
GC_Public_Announce public_announce;
|
||||
|
||||
// TODO(iphydf): How do we know the packed size?
|
||||
CONSUME1_OR_RETURN(const uint16_t packed_size, input);
|
||||
|
||||
Logger *logger = logger_new();
|
||||
if (gca_unpack_public_announce(logger, input.data, input.size, &public_announce) != -1) {
|
||||
std::vector<uint8_t> packed(packed_size);
|
||||
gca_pack_public_announce(logger, packed.data(), packed.size(), &public_announce);
|
||||
}
|
||||
logger_kill(logger);
|
||||
}
|
||||
|
||||
void TestDoGca(Fuzz_Data &input)
|
||||
{
|
||||
std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(), logger_kill);
|
||||
std::unique_ptr<Mono_Time, void (*)(Mono_Time *)> mono_time(
|
||||
mono_time_new(nullptr, nullptr), mono_time_free);
|
||||
assert(mono_time != nullptr);
|
||||
uint64_t clock = 1;
|
||||
mono_time_set_current_time_callback(
|
||||
mono_time.get(), [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
|
||||
&clock);
|
||||
std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(new_gca_list(), kill_gca);
|
||||
assert(gca != nullptr);
|
||||
|
||||
while (input.size > 0) {
|
||||
CONSUME1_OR_RETURN(const uint8_t choice, input);
|
||||
switch (choice) {
|
||||
case 0: {
|
||||
// Add an announce.
|
||||
CONSUME1_OR_RETURN(const uint16_t length, input);
|
||||
CONSUME_OR_RETURN(const uint8_t *data, input, length);
|
||||
GC_Public_Announce public_announce;
|
||||
if (gca_unpack_public_announce(logger.get(), data, length, &public_announce) != -1) {
|
||||
gca_add_announce(mono_time.get(), gca.get(), &public_announce);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Advance the time by a number of tox_iteration_intervals.
|
||||
CONSUME1_OR_RETURN(const uint8_t iterations, input);
|
||||
clock += iterations * 20;
|
||||
// Do an iteration.
|
||||
do_gca(mono_time.get(), gca.get());
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// Get announces.
|
||||
CONSUME1_OR_RETURN(const uint8_t max_nodes, input);
|
||||
std::vector<GC_Announce> gc_announces(max_nodes);
|
||||
CONSUME_OR_RETURN(const uint8_t *chat_id, input, CHAT_ID_SIZE);
|
||||
CONSUME_OR_RETURN(const uint8_t *except_public_key, input, ENC_PUBLIC_KEY_SIZE);
|
||||
gca_get_announces(
|
||||
gca.get(), gc_announces.data(), max_nodes, chat_id, except_public_key);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// Remove a chat.
|
||||
CONSUME_OR_RETURN(const uint8_t *chat_id, input, CHAT_ID_SIZE);
|
||||
cleanup_gca(gca.get(), chat_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
fuzz_select_target(data, size, TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca);
|
||||
return 0;
|
||||
}
|
261
external/toxcore/c-toxcore/toxcore/group_announce_test.cc
vendored
Normal file
261
external/toxcore/c-toxcore/toxcore/group_announce_test.cc
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
#include "group_announce.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mono_time.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Announces : ::testing::Test {
|
||||
protected:
|
||||
uint64_t clock_ = 0;
|
||||
Mono_Time *mono_time_ = nullptr;
|
||||
GC_Announces_List *gca_ = nullptr;
|
||||
GC_Announce _ann1;
|
||||
GC_Announce _ann2;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
mono_time_ = mono_time_new(nullptr, nullptr);
|
||||
ASSERT_NE(mono_time_, nullptr);
|
||||
mono_time_set_current_time_callback(
|
||||
mono_time_, [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
|
||||
&clock_);
|
||||
gca_ = new_gca_list();
|
||||
ASSERT_NE(gca_, nullptr);
|
||||
}
|
||||
|
||||
~Announces() override
|
||||
{
|
||||
kill_gca(gca_);
|
||||
mono_time_free(mono_time_);
|
||||
}
|
||||
|
||||
void advance_clock(uint64_t increment)
|
||||
{
|
||||
clock_ += increment;
|
||||
mono_time_update(mono_time_);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Announces, KillGcaOnNullptrIsNoop)
|
||||
{
|
||||
// All kill functions should be nullable.
|
||||
kill_gca(nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Announces, CanBeCreatedAndDeleted)
|
||||
{
|
||||
GC_Public_Announce ann{};
|
||||
ann.chat_public_key[0] = 0x88;
|
||||
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann), nullptr);
|
||||
ASSERT_EQ(gca_add_announce(mono_time_, gca_, nullptr), nullptr);
|
||||
ASSERT_EQ(gca_add_announce(mono_time_, nullptr, &ann), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Announces, AnnouncesCanTimeOut)
|
||||
{
|
||||
advance_clock(100);
|
||||
ASSERT_EQ(gca_->root_announces, nullptr);
|
||||
GC_Public_Announce ann{};
|
||||
ann.chat_public_key[0] = 0xae;
|
||||
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann), nullptr);
|
||||
ASSERT_NE(gca_->root_announces, nullptr);
|
||||
ASSERT_EQ(gca_->root_announces->chat_id[0], 0xae);
|
||||
|
||||
// One iteration without having any time passed => announce is still here.
|
||||
do_gca(mono_time_, gca_);
|
||||
ASSERT_NE(gca_->root_announces, nullptr);
|
||||
|
||||
// 29 seconds later, still there
|
||||
advance_clock(29000);
|
||||
do_gca(mono_time_, gca_);
|
||||
ASSERT_NE(gca_->root_announces, nullptr);
|
||||
|
||||
// One more second and it's gone.
|
||||
advance_clock(1000);
|
||||
do_gca(mono_time_, gca_);
|
||||
ASSERT_EQ(gca_->root_announces, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Announces, AnnouncesGetAndCleanup)
|
||||
{
|
||||
GC_Public_Announce ann1{};
|
||||
GC_Public_Announce ann2{};
|
||||
ann1.chat_public_key[0] = 0x91;
|
||||
ann1.base_announce.peer_public_key[0] = 0x7f;
|
||||
ann2.chat_public_key[0] = 0x92;
|
||||
ann2.base_announce.peer_public_key[0] = 0x7c;
|
||||
|
||||
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann1), nullptr);
|
||||
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann2), nullptr);
|
||||
ASSERT_NE(gca_add_announce(mono_time_, gca_, &ann2), nullptr);
|
||||
|
||||
uint8_t empty_pk[ENC_PUBLIC_KEY_SIZE] = {0};
|
||||
|
||||
GC_Announce announces;
|
||||
ASSERT_EQ(gca_get_announces(gca_, &announces, 1, ann1.chat_public_key, empty_pk), 1);
|
||||
ASSERT_EQ(gca_get_announces(gca_, &announces, 1, ann2.chat_public_key, empty_pk), 1);
|
||||
|
||||
cleanup_gca(gca_, ann1.chat_public_key);
|
||||
ASSERT_EQ(gca_get_announces(gca_, &announces, 1, ann1.chat_public_key, empty_pk), 0);
|
||||
|
||||
cleanup_gca(gca_, ann2.chat_public_key);
|
||||
ASSERT_EQ(gca_get_announces(gca_, &announces, 1, ann2.chat_public_key, empty_pk), 0);
|
||||
ASSERT_EQ(gca_get_announces(gca_, nullptr, 1, ann2.chat_public_key, empty_pk), -1);
|
||||
}
|
||||
|
||||
struct AnnouncesPack : ::testing::Test {
|
||||
protected:
|
||||
std::vector<GC_Announce> announces_;
|
||||
Logger *logger_ = nullptr;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
logger_ = logger_new();
|
||||
ASSERT_NE(logger_, nullptr);
|
||||
|
||||
// Add an announce without TCP relay.
|
||||
announces_.emplace_back();
|
||||
auto &ann1 = announces_.back();
|
||||
|
||||
ann1.peer_public_key[0] = 0xae;
|
||||
ann1.ip_port.ip.family = net_family_ipv4();
|
||||
ann1.ip_port.ip.ip.v4.uint8[0] = 0x7f; // 127.0.0.1
|
||||
ann1.ip_port.ip.ip.v4.uint8[3] = 0x1;
|
||||
ann1.ip_port_is_set = 1;
|
||||
|
||||
// Add an announce with TCP relay.
|
||||
announces_.emplace_back();
|
||||
auto &ann2 = announces_.back();
|
||||
|
||||
ann2.peer_public_key[0] = 0xaf; // different key
|
||||
ann2.ip_port.ip.family = net_family_ipv4();
|
||||
ann2.ip_port.ip.ip.v4.uint8[0] = 0x7f; // 127.0.0.2
|
||||
ann2.ip_port.ip.ip.v4.uint8[3] = 0x2;
|
||||
ann2.ip_port_is_set = 1;
|
||||
ann2.tcp_relays_count = 1;
|
||||
ann2.tcp_relays[0].ip_port.ip.family = net_family_ipv4();
|
||||
ann2.tcp_relays[0].ip_port.ip.ip.v4 = ip4_broadcast;
|
||||
ann2.tcp_relays[0].public_key[0] = 0xea;
|
||||
}
|
||||
|
||||
~AnnouncesPack() override { logger_kill(logger_); }
|
||||
};
|
||||
|
||||
TEST_F(AnnouncesPack, PublicAnnounceCanBePackedAndUnpacked)
|
||||
{
|
||||
GC_Public_Announce ann{};
|
||||
ann.chat_public_key[0] = 0x88;
|
||||
ann.base_announce = announces_[0];
|
||||
|
||||
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
|
||||
const int packed_size = gca_pack_public_announce(logger_, packed.data(), packed.size(), &ann);
|
||||
|
||||
EXPECT_GT(packed_size, 0);
|
||||
|
||||
GC_Public_Announce unpacked_ann{};
|
||||
EXPECT_EQ(gca_unpack_public_announce(logger_, packed.data(), packed.size(), &unpacked_ann),
|
||||
packed_size);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, UnpackEmptyPublicAnnounce)
|
||||
{
|
||||
GC_Public_Announce ann{};
|
||||
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
|
||||
|
||||
EXPECT_EQ(gca_unpack_public_announce(logger_, nullptr, 0, &ann), -1);
|
||||
EXPECT_EQ(gca_unpack_public_announce(logger_, packed.data(), packed.size(), nullptr), -1);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, PackEmptyPublicAnnounce)
|
||||
{
|
||||
GC_Public_Announce ann{};
|
||||
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
|
||||
EXPECT_EQ(gca_pack_public_announce(logger_, packed.data(), packed.size(), nullptr), -1);
|
||||
EXPECT_EQ(gca_pack_public_announce(logger_, nullptr, 0, &ann), -1);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, PublicAnnouncePackNull)
|
||||
{
|
||||
GC_Public_Announce ann{};
|
||||
std::vector<uint8_t> packed(GCA_PUBLIC_ANNOUNCE_MAX_SIZE);
|
||||
EXPECT_EQ(gca_pack_public_announce(logger_, packed.data(), packed.size(), &ann), -1);
|
||||
|
||||
ann.chat_public_key[0] = 0x88;
|
||||
ann.base_announce = announces_[0];
|
||||
|
||||
std::vector<uint8_t> packedTooSmall(GCA_PUBLIC_ANNOUNCE_MAX_SIZE - 1);
|
||||
EXPECT_EQ(
|
||||
gca_pack_public_announce(logger_, packedTooSmall.data(), packedTooSmall.size(), &ann), -1);
|
||||
|
||||
ann.base_announce.ip_port_is_set = 0;
|
||||
ann.base_announce.tcp_relays_count = 0;
|
||||
|
||||
EXPECT_EQ(gca_pack_public_announce(logger_, packed.data(), packed.size(), &ann), -1);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, AnnouncesValidationCheck)
|
||||
{
|
||||
EXPECT_EQ(gca_is_valid_announce(nullptr), false);
|
||||
|
||||
GC_Announce announce = {0};
|
||||
EXPECT_EQ(gca_is_valid_announce(&announce), false);
|
||||
EXPECT_EQ(gca_is_valid_announce(&announces_[0]), true);
|
||||
EXPECT_EQ(gca_is_valid_announce(&announces_[1]), true);
|
||||
announces_[0].ip_port_is_set = 0;
|
||||
announces_[0].tcp_relays_count = 0;
|
||||
EXPECT_EQ(gca_is_valid_announce(&announces_[0]), false);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, UnpackIncompleteAnnouncesList)
|
||||
{
|
||||
const uint8_t data[] = {0x00, 0x24, 0x3d, 0x00, 0x3d, 0xff, 0xff, 0x5b, 0x04, 0x20, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
|
||||
|
||||
GC_Announce announce;
|
||||
EXPECT_EQ(gca_unpack_announces_list(logger_, data, sizeof(data), &announce, 1), -1);
|
||||
EXPECT_EQ(gca_unpack_announces_list(logger_, data, sizeof(data), nullptr, 1), -1);
|
||||
EXPECT_EQ(gca_unpack_announces_list(logger_, nullptr, 0, &announce, 1), -1);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, PackedAnnouncesListCanBeUnpacked)
|
||||
{
|
||||
const uint16_t size = gca_pack_announces_list_size(announces_.size());
|
||||
std::vector<uint8_t> packed(size);
|
||||
|
||||
size_t processed = 0;
|
||||
|
||||
EXPECT_GT(gca_pack_announces_list(logger_, packed.data(), packed.size(), announces_.data(),
|
||||
announces_.size(), &processed),
|
||||
0);
|
||||
ASSERT_GE(processed, ENC_PUBLIC_KEY_SIZE + 2);
|
||||
ASSERT_LE(processed, size);
|
||||
|
||||
std::vector<GC_Announce> announces_unpacked(announces_.size());
|
||||
ASSERT_EQ(gca_unpack_announces_list(logger_, packed.data(), packed.size(),
|
||||
announces_unpacked.data(), announces_unpacked.size()),
|
||||
announces_unpacked.size());
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, PackingEmptyAnnounceFails)
|
||||
{
|
||||
GC_Announce announce{}; // all zeroes
|
||||
std::vector<uint8_t> packed(gca_pack_announces_list_size(1));
|
||||
EXPECT_EQ(
|
||||
gca_pack_announces_list(logger_, packed.data(), packed.size(), &announce, 1, nullptr), -1);
|
||||
EXPECT_EQ(
|
||||
gca_pack_announces_list(logger_, packed.data(), packed.size(), nullptr, 1, nullptr), -1);
|
||||
EXPECT_EQ(gca_pack_announces_list(logger_, nullptr, 0, &announce, 1, nullptr), -1);
|
||||
}
|
||||
|
||||
TEST_F(AnnouncesPack, PackAnnounceNull)
|
||||
{
|
||||
std::vector<uint8_t> data(GCA_ANNOUNCE_MAX_SIZE);
|
||||
GC_Announce announce;
|
||||
ASSERT_EQ(gca_pack_announce(logger_, nullptr, 0, &announce), -1);
|
||||
ASSERT_EQ(gca_pack_announce(logger_, data.data(), data.size(), nullptr), -1);
|
||||
}
|
||||
|
||||
} // namespace
|
8410
external/toxcore/c-toxcore/toxcore/group_chats.c
vendored
Normal file
8410
external/toxcore/c-toxcore/toxcore/group_chats.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
782
external/toxcore/c-toxcore/toxcore/group_chats.h
vendored
Normal file
782
external/toxcore/c-toxcore/toxcore/group_chats.h
vendored
Normal file
@ -0,0 +1,782 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of massive text only group chats.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_CHATS_H
|
||||
#define GROUP_CHATS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "TCP_connection.h"
|
||||
#include "bin_pack.h"
|
||||
#include "bin_unpack.h"
|
||||
#include "group_announce.h"
|
||||
#include "group_common.h"
|
||||
#include "group_connection.h"
|
||||
#include "logger.h"
|
||||
|
||||
#define GC_PING_TIMEOUT 12
|
||||
#define GC_SEND_IP_PORT_INTERVAL (GC_PING_TIMEOUT * 5)
|
||||
#define GC_CONFIRMED_PEER_TIMEOUT (GC_PING_TIMEOUT * 4 + 10)
|
||||
#define GC_UNCONFIRMED_PEER_TIMEOUT GC_PING_TIMEOUT
|
||||
|
||||
#define GC_JOIN_DATA_LENGTH (ENC_PUBLIC_KEY_SIZE + CHAT_ID_SIZE)
|
||||
|
||||
/** Group topic lock states. */
|
||||
typedef enum Group_Topic_Lock {
|
||||
TL_ENABLED = 0x00, // Only the Founder and moderators may set the topic
|
||||
TL_DISABLED = 0x01, // Anyone except Observers may set the topic
|
||||
} Group_Topic_Lock;
|
||||
|
||||
/** Group moderation events. */
|
||||
typedef enum Group_Moderation_Event {
|
||||
MV_KICK = 0x00, // A peer has been kicked
|
||||
MV_OBSERVER = 0x01, // A peer has been demoted to Observer
|
||||
MV_USER = 0x02, // A peer has been demoted or promoted to User
|
||||
MV_MOD = 0x03, // A peer has been promoted to or demoted from Moderator
|
||||
} Group_Moderation_Event;
|
||||
|
||||
/** Messenger level group invite types */
|
||||
typedef enum Group_Invite_Message_Type {
|
||||
GROUP_INVITE = 0x00, // Peer has initiated an invite
|
||||
GROUP_INVITE_ACCEPTED = 0x01, // Peer has accepted the invite
|
||||
GROUP_INVITE_CONFIRMATION = 0x02, // Peer has confirmed the accepted invite
|
||||
} Group_Invite_Message_Type;
|
||||
|
||||
/** Group join rejection types. */
|
||||
typedef enum Group_Join_Rejected {
|
||||
GJ_GROUP_FULL = 0x00,
|
||||
GJ_INVALID_PASSWORD = 0x01,
|
||||
GJ_INVITE_FAILED = 0x02,
|
||||
GJ_INVALID = 0x03,
|
||||
} Group_Join_Rejected;
|
||||
|
||||
/** Group broadcast packet types */
|
||||
typedef enum Group_Broadcast_Type {
|
||||
GM_STATUS = 0x00, // Peer changed their status
|
||||
GM_NICK = 0x01, // Peer changed their nickname
|
||||
GM_PLAIN_MESSAGE = 0x02, // Peer sent a normal message
|
||||
GM_ACTION_MESSAGE = 0x03, // Peer sent an action message
|
||||
GM_PRIVATE_MESSAGE = 0x04, // Peer sent a private message
|
||||
GM_PEER_EXIT = 0x05, // Peer left the group
|
||||
GM_KICK_PEER = 0x06, // Peer was kicked from the group
|
||||
GM_SET_MOD = 0x07, // Peer was promoted to or demoted from Moderator role
|
||||
GM_SET_OBSERVER = 0x08, // Peer was demoted to or promoted from Observer role
|
||||
} Group_Broadcast_Type;
|
||||
|
||||
/***
|
||||
* Group packet types.
|
||||
*
|
||||
* For a detailed spec, see docs/DHT_Group_Chats_Packet_Spec.md
|
||||
*/
|
||||
typedef enum Group_Packet_Type {
|
||||
/* lossy packets (ID 0 is reserved) */
|
||||
GP_PING = 0x01,
|
||||
GP_MESSAGE_ACK = 0x02,
|
||||
GP_INVITE_RESPONSE_REJECT = 0x03,
|
||||
|
||||
/* lossless packets */
|
||||
GP_CUSTOM_PRIVATE_PACKET = 0xee,
|
||||
GP_FRAGMENT = 0xef,
|
||||
GP_KEY_ROTATION = 0xf0,
|
||||
GP_TCP_RELAYS = 0xf1,
|
||||
GP_CUSTOM_PACKET = 0xf2,
|
||||
GP_BROADCAST = 0xf3,
|
||||
GP_PEER_INFO_REQUEST = 0xf4,
|
||||
GP_PEER_INFO_RESPONSE = 0xf5,
|
||||
GP_INVITE_REQUEST = 0xf6,
|
||||
GP_INVITE_RESPONSE = 0xf7,
|
||||
GP_SYNC_REQUEST = 0xf8,
|
||||
GP_SYNC_RESPONSE = 0xf9,
|
||||
GP_TOPIC = 0xfa,
|
||||
GP_SHARED_STATE = 0xfb,
|
||||
GP_MOD_LIST = 0xfc,
|
||||
GP_SANCTIONS_LIST = 0xfd,
|
||||
GP_FRIEND_INVITE = 0xfe,
|
||||
GP_HS_RESPONSE_ACK = 0xff,
|
||||
} Group_Packet_Type;
|
||||
|
||||
/** Lossless message acknowledgement types. */
|
||||
typedef enum Group_Message_Ack_Type {
|
||||
GR_ACK_RECV = 0x00, // indicates a message has been received
|
||||
GR_ACK_REQ = 0x01, // indicates a message needs to be re-sent
|
||||
} Group_Message_Ack_Type;
|
||||
|
||||
/** @brief Returns the GC_Connection object associated with `peer_number`.
|
||||
* Returns null if peer_number does not designate a valid peer.
|
||||
*/
|
||||
non_null()
|
||||
GC_Connection *get_gc_connection(const GC_Chat *chat, int peer_number);
|
||||
|
||||
/** @brief Returns the jenkins hash of a 32 byte public encryption key. */
|
||||
non_null()
|
||||
uint32_t gc_get_pk_jenkins_hash(const uint8_t *public_key);
|
||||
|
||||
/** @brief Check if peer with the public encryption key is in peer list.
|
||||
*
|
||||
* Returns the peer number if peer is in the peer list.
|
||||
* Returns -1 if peer is not in the peer list.
|
||||
*
|
||||
* If `confirmed` is true the peer number will only be returned if the peer is confirmed.
|
||||
*/
|
||||
non_null()
|
||||
int get_peer_number_of_enc_pk(const GC_Chat *chat, const uint8_t *public_enc_key, bool confirmed);
|
||||
|
||||
/** @brief Encrypts `data` of size `length` using the peer's shared key and a new nonce.
|
||||
*
|
||||
* Adds encrypted header consisting of: packet type, message_id (only for lossless packets).
|
||||
* Adds plaintext header consisting of: packet identifier, self public encryption key, nonce.
|
||||
*
|
||||
* Return length of encrypted packet on success.
|
||||
* Return -1 if plaintext length is invalid.
|
||||
* Return -2 if malloc fails.
|
||||
* Return -3 if encryption fails.
|
||||
*/
|
||||
non_null(1, 2, 3, 4, 5) nullable(7)
|
||||
int group_packet_wrap(
|
||||
const Logger *log, 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, uint8_t net_packet_type);
|
||||
|
||||
/** @brief Returns the size of a wrapped/encrypted packet with a plain size of `length`.
|
||||
*
|
||||
* `packet_type` should be either NET_PACKET_GC_LOSSY or NET_PACKET_GC_LOSSLESS.
|
||||
*/
|
||||
uint16_t gc_get_wrapped_packet_size(uint16_t length, Net_Packet_Type packet_type);
|
||||
|
||||
/** @brief Sends a plain message or an action, depending on type.
|
||||
*
|
||||
* `length` must not exceed MAX_GC_MESSAGE_SIZE and must not be equal to zero.
|
||||
* `message_id` should either point to a uint32_t or be NULL.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the message is too long.
|
||||
* Returns -2 if the message pointer is NULL or length is zero.
|
||||
* Returns -3 if the message type is invalid.
|
||||
* Returns -4 if the sender does not have permission to speak.
|
||||
* Returns -5 if the packet fails to send.
|
||||
*/
|
||||
non_null(1, 2, 3, 4) nullable(5)
|
||||
int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length, uint8_t type,
|
||||
uint32_t *message_id);
|
||||
|
||||
/** @brief Sends a private message to peer_id.
|
||||
*
|
||||
* `length` must not exceed MAX_GC_MESSAGE_SIZE and must not be equal to zero.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the message is too long.
|
||||
* Returns -2 if the message pointer is NULL or length is zero.
|
||||
* Returns -3 if the peer_id is invalid.
|
||||
* Returns -4 if the message type is invalid.
|
||||
* Returns -5 if the sender has the observer role.
|
||||
* Returns -6 if the packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_send_private_message(const GC_Chat *chat, uint32_t peer_id, uint8_t type, const uint8_t *message,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Sends a custom packet to the group. If lossless is true, the packet will be lossless.
|
||||
*
|
||||
* `length` must not exceed MAX_GC_MESSAGE_SIZE and must not be equal to zero.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the message is too long.
|
||||
* Returns -2 if the message pointer is NULL or length is zero.
|
||||
* Returns -3 if the sender has the observer role.
|
||||
*/
|
||||
non_null()
|
||||
int gc_send_custom_packet(const GC_Chat *chat, bool lossless, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief Sends a custom private packet to the peer designated by peer_id.
|
||||
*
|
||||
* `length` must not exceed MAX_GC_MESSAGE_SIZE and must not be equal to zero.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if the message is too long.
|
||||
* @retval -2 if the message pointer is NULL or length is zero.
|
||||
* @retval -3 if the supplied peer_id does not designate a valid peer.
|
||||
* @retval -4 if the sender has the observer role.
|
||||
* @retval -5 if the packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_send_custom_private_packet(const GC_Chat *chat, bool lossless, uint32_t peer_id, const uint8_t *message,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Sets ignore for peer_id.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the peer_id is invalid.
|
||||
* Returns -2 if the caller attempted to ignore himself.
|
||||
*/
|
||||
non_null()
|
||||
int gc_set_ignore(const GC_Chat *chat, uint32_t peer_id, bool ignore);
|
||||
|
||||
/** @brief Sets the group topic and broadcasts it to the group.
|
||||
*
|
||||
* If `length` is equal to zero the topic will be unset.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the topic is too long (must be `<= MAX_GC_TOPIC_SIZE`).
|
||||
* Returns -2 if the caller does not have the required permissions to set the topic.
|
||||
* Returns -3 if the packet cannot be created or signing fails.
|
||||
* Returns -4 if the packet fails
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length);
|
||||
|
||||
/** @brief Copies the group topic to `topic`. If topic is null this function has no effect.
|
||||
*
|
||||
* Call `gc_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 topic callback.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
void gc_get_topic(const GC_Chat *chat, uint8_t *topic);
|
||||
|
||||
/** @brief Returns the topic length.
|
||||
*
|
||||
* The return value is equal to the `length` agument received by the last topic callback.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t gc_get_topic_size(const GC_Chat *chat);
|
||||
|
||||
/** @brief Copies group name to `group_name`. If `group_name` is null this function has no effect.
|
||||
*
|
||||
* Call `gc_get_group_name_size` to determine the allocation size for the `group_name`
|
||||
* parameter.
|
||||
*/
|
||||
non_null()
|
||||
void gc_get_group_name(const GC_Chat *chat, uint8_t *group_name);
|
||||
|
||||
/** @brief Returns the group name length. */
|
||||
non_null()
|
||||
uint16_t gc_get_group_name_size(const GC_Chat *chat);
|
||||
|
||||
/** @brief Copies the group password to password.
|
||||
*
|
||||
* If password is null this function has no effect.
|
||||
*
|
||||
* Call the `gc_get_password_size` function to determine the allocation size for
|
||||
* the `password` buffer.
|
||||
*
|
||||
* The data received is equal to the data received by the last password callback.
|
||||
*/
|
||||
non_null()
|
||||
void gc_get_password(const GC_Chat *chat, uint8_t *password);
|
||||
|
||||
/** @brief Returns the group password length. */
|
||||
non_null()
|
||||
uint16_t gc_get_password_size(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns the group privacy state.
|
||||
*
|
||||
* The value returned is equal to the data receieved by the last privacy_state callback.
|
||||
*/
|
||||
non_null()
|
||||
Group_Privacy_State gc_get_privacy_state(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns the group topic lock state.
|
||||
*
|
||||
* The value returned is equal to the data received by the last last topic_lock callback.
|
||||
*/
|
||||
non_null()
|
||||
Group_Topic_Lock gc_get_topic_lock_state(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns the group voice state.
|
||||
*
|
||||
* The value returned is equal to the data received by the last voice_state callback.
|
||||
*/
|
||||
non_null()
|
||||
Group_Voice_State gc_get_voice_state(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns the group peer limit.
|
||||
*
|
||||
* The value returned is equal to the data receieved by the last peer_limit callback.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t gc_get_max_peers(const GC_Chat *chat);
|
||||
|
||||
/** @brief Sets your own nick to `nick`.
|
||||
*
|
||||
* `length` cannot exceed MAX_GC_NICK_SIZE. if `length` is zero or `name` is a
|
||||
* null pointer the function call will fail.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if group_number is invalid.
|
||||
* Returns -2 if the length is too long.
|
||||
* Returns -3 if the length is zero or nick is a NULL pointer.
|
||||
* Returns -4 if the packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_set_self_nick(const Messenger *m, int group_number, const uint8_t *nick, uint16_t length);
|
||||
|
||||
/** @brief Copies your own name to `nick`.
|
||||
*
|
||||
* If `nick` is null this function has no effect.
|
||||
*/
|
||||
non_null()
|
||||
void gc_get_self_nick(const GC_Chat *chat, uint8_t *nick);
|
||||
|
||||
/** @brief Return your own nick length.
|
||||
*
|
||||
* If no nick was set before calling this function it will return 0.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t gc_get_self_nick_size(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns your own group role. */
|
||||
non_null()
|
||||
Group_Role gc_get_self_role(const GC_Chat *chat);
|
||||
|
||||
/** @brief Return your own status. */
|
||||
non_null()
|
||||
uint8_t gc_get_self_status(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns your own peer id. */
|
||||
non_null()
|
||||
uint32_t gc_get_self_peer_id(const GC_Chat *chat);
|
||||
|
||||
/** @brief Copies self public key to `public_key`.
|
||||
*
|
||||
* If `public_key` is null this function has no effect.
|
||||
*
|
||||
* This key is permanently tied to our identity for `chat` until we explicitly
|
||||
* exit the group. This key is the only way for other peers to reliably identify
|
||||
* us across client restarts.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
void gc_get_self_public_key(const GC_Chat *chat, uint8_t *public_key);
|
||||
|
||||
/** @brief Copies nick designated by `peer_id` to `name`.
|
||||
*
|
||||
* Call `gc_get_peer_nick_size` to determine the allocation size for the `name` parameter.
|
||||
*
|
||||
* The data written to `name` is equal to the data received by the last nick_change callback.
|
||||
*
|
||||
* Returns true on success.
|
||||
* Returns false if peer_id is invalid.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
bool gc_get_peer_nick(const GC_Chat *chat, uint32_t peer_id, uint8_t *name);
|
||||
|
||||
/** @brief Returns the length of the nick for the peer designated by `peer_id`.
|
||||
* Returns -1 if peer_id is invalid.
|
||||
*
|
||||
* The value returned is equal to the `length` argument received by the last
|
||||
* nick_change callback.
|
||||
*/
|
||||
non_null()
|
||||
int gc_get_peer_nick_size(const GC_Chat *chat, uint32_t peer_id);
|
||||
|
||||
/** @brief Copies peer_id's public key to `public_key`.
|
||||
*
|
||||
* This key is permanently tied to the peer's identity for `chat` until they explicitly
|
||||
* exit the group. This key is the only way for to reliably identify the given peer
|
||||
* across client restarts.
|
||||
*
|
||||
* `public_key` shold have room for at least ENC_PUBLIC_KEY_SIZE bytes.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if peer_id is invalid or doesn't correspond to a valid peer connection.
|
||||
* Returns -2 if `public_key` is null.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uint8_t *public_key);
|
||||
|
||||
/** @brief Gets the connection status for peer associated with `peer_id`.
|
||||
*
|
||||
* Returns 2 if we have a direct (UDP) connection with a peer.
|
||||
* Returns 1 if we have an indirect (TCP) connection with a peer.
|
||||
* Returns 0 if peer_id is invalid or corresponds to ourselves.
|
||||
*
|
||||
* Note: Return values must correspond to Tox_Connection enum in API.
|
||||
*/
|
||||
non_null()
|
||||
unsigned int gc_get_peer_connection_status(const GC_Chat *chat, uint32_t peer_id);
|
||||
|
||||
/** @brief Sets the caller's status to `status`.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the group_number is invalid.
|
||||
* Returns -2 if the packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_set_self_status(const Messenger *m, int group_number, Group_Peer_Status status);
|
||||
|
||||
/** @brief Returns the status of peer designated by `peer_id`.
|
||||
* Returns UINT8_MAX on failure.
|
||||
*
|
||||
* The status returned is equal to the last status received through the status_change
|
||||
* callback.
|
||||
*/
|
||||
non_null()
|
||||
uint8_t gc_get_status(const GC_Chat *chat, uint32_t peer_id);
|
||||
|
||||
/** @brief Returns the group role of peer designated by `peer_id`.
|
||||
* Returns UINT8_MAX on failure.
|
||||
*
|
||||
* The role returned is equal to the last role received through the moderation callback.
|
||||
*/
|
||||
non_null()
|
||||
uint8_t gc_get_role(const GC_Chat *chat, uint32_t peer_id);
|
||||
|
||||
/** @brief Sets the role of peer_id. role must be one of: GR_MODERATOR, GR_USER, GR_OBSERVER
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the group_number is invalid.
|
||||
* Returns -2 if the peer_id is invalid.
|
||||
* Returns -3 if caller does not have sufficient permissions for the action.
|
||||
* Returns -4 if the role assignment is invalid.
|
||||
* Returns -5 if the role failed to be set.
|
||||
* Returns -6 if the caller attempted to kick himself.
|
||||
*/
|
||||
non_null()
|
||||
int gc_set_peer_role(const Messenger *m, int group_number, uint32_t peer_id, Group_Role new_role);
|
||||
|
||||
/** @brief Sets the group password and distributes the new shared state to the group.
|
||||
*
|
||||
* This function requires that the shared state be re-signed and will only work for the group founder.
|
||||
*
|
||||
* If `password` is null or `password_length` is 0 the password will be unset for the group.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the caller does not have sufficient permissions for the action.
|
||||
* Returns -2 if the password is too long.
|
||||
* Returns -3 if the packet failed to send.
|
||||
* Returns -4 if malloc failed.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t password_length);
|
||||
|
||||
/** @brief Sets the topic lock and distributes the new shared state to 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.
|
||||
*
|
||||
* This function requires that the shared state be re-signed and will only work for the group founder.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if group_number is invalid.
|
||||
* Returns -2 if `topic_lock` is an invalid type.
|
||||
* Returns -3 if the caller does not have sufficient permissions for this action.
|
||||
* Returns -4 if the group is disconnected.
|
||||
* Returns -5 if the topic lock could not be set.
|
||||
* Returns -6 if the packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_founder_set_topic_lock(const Messenger *m, int group_number, Group_Topic_Lock new_lock_state);
|
||||
|
||||
/** @brief Sets the group privacy state and distributes the new shared state to the group.
|
||||
*
|
||||
* This function requires that the shared state be re-signed and will only work for the group founder.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if group_number is invalid.
|
||||
* Returns -2 if the caller does not have sufficient permissions for this action.
|
||||
* Returns -3 if the group is disconnected.
|
||||
* Returns -4 if the privacy state could not be set.
|
||||
* Returns -5 if the packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_founder_set_privacy_state(const Messenger *m, int group_number, Group_Privacy_State new_privacy_state);
|
||||
|
||||
/** @brief Sets the group voice state and distributes the new shared state to the group.
|
||||
*
|
||||
* This function requires that the shared state be re-signed and will only work for the group founder.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if group_number is invalid.
|
||||
* Returns -2 if the caller does not have sufficient permissions for this action.
|
||||
* Returns -3 if the group is disconnected.
|
||||
* Returns -4 if the voice state could not be set.
|
||||
* Returns -5 if the packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_founder_set_voice_state(const Messenger *m, int group_number, Group_Voice_State new_voice_state);
|
||||
|
||||
/** @brief Sets the peer limit to maxpeers and distributes the new shared state to the group.
|
||||
*
|
||||
* This function requires that the shared state be re-signed and will only work for the group founder.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the caller does not have sufficient permissions for this action.
|
||||
* Returns -2 if the peer limit could not be set.
|
||||
* Returns -3 if the packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_founder_set_max_peers(GC_Chat *chat, uint16_t max_peers);
|
||||
|
||||
/** @brief Removes peer designated by `peer_id` from peer list and sends a broadcast instructing
|
||||
* all other peers to remove the peer from their peerlist as well.
|
||||
*
|
||||
* This function will not trigger the peer_exit callback for the caller.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 if the group_number is invalid.
|
||||
* Returns -2 if the peer_id is invalid.
|
||||
* Returns -3 if the caller does not have sufficient permissions for this action.
|
||||
* Returns -4 if the action failed.
|
||||
* Returns -5 if the packet failed to send.
|
||||
* Returns -6 if the caller attempted to kick himself.
|
||||
*/
|
||||
non_null()
|
||||
int gc_kick_peer(const Messenger *m, int group_number, uint32_t peer_id);
|
||||
|
||||
/** @brief Copies the chat_id to dest. If dest is null this function has no effect.
|
||||
*
|
||||
* `dest` should have room for at least CHAT_ID_SIZE bytes.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
void gc_get_chat_id(const GC_Chat *chat, uint8_t *dest);
|
||||
|
||||
|
||||
/** Group callbacks */
|
||||
non_null(1) nullable(2) void gc_callback_message(const Messenger *m, gc_message_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_private_message(const Messenger *m, gc_private_message_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_custom_packet(const Messenger *m, gc_custom_packet_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_custom_private_packet(const Messenger *m,
|
||||
gc_custom_private_packet_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_moderation(const Messenger *m, gc_moderation_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_nick_change(const Messenger *m, gc_nick_change_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_status_change(const Messenger *m, gc_status_change_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_topic_change(const Messenger *m, gc_topic_change_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_peer_limit(const Messenger *m, gc_peer_limit_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_privacy_state(const Messenger *m, gc_privacy_state_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_topic_lock(const Messenger *m, gc_topic_lock_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_password(const Messenger *m, gc_password_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_peer_join(const Messenger *m, gc_peer_join_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_peer_exit(const Messenger *m, gc_peer_exit_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_self_join(const Messenger *m, gc_self_join_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_rejected(const Messenger *m, gc_rejected_cb *function);
|
||||
non_null(1) nullable(2) void gc_callback_voice_state(const Messenger *m, gc_voice_state_cb *function);
|
||||
|
||||
/** @brief The main loop. Should be called with every Messenger iteration. */
|
||||
non_null(1) nullable(2)
|
||||
void do_gc(GC_Session *c, void *userdata);
|
||||
|
||||
/**
|
||||
* Make sure that DHT is initialized before calling this.
|
||||
* Returns a NULL pointer on failure.
|
||||
*/
|
||||
nullable(1)
|
||||
GC_Session *new_dht_groupchats(Messenger *m);
|
||||
|
||||
/** @brief Cleans up groupchat structures and calls `gc_group_exit()` for every group chat */
|
||||
nullable(1)
|
||||
void kill_dht_groupchats(GC_Session *c);
|
||||
|
||||
/** @brief Loads a previously saved group and attempts to join it.
|
||||
*
|
||||
* `bu` is the packed group info.
|
||||
*
|
||||
* Returns group_number on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gc_group_load(GC_Session *c, Bin_Unpack *bu);
|
||||
|
||||
/**
|
||||
* @brief Saves info from `chat` to `bp` in binary format.
|
||||
*/
|
||||
non_null()
|
||||
void gc_group_save(const GC_Chat *chat, Bin_Pack *bp);
|
||||
|
||||
/** @brief Creates a new group and adds it to the group sessions group array.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Return -1 if the nick or group name is too long.
|
||||
* Return -2 if the nick or group name is empty.
|
||||
* Return -3 if the the group object fails to initialize.
|
||||
* Return -4 if the group state fails to initialize.
|
||||
* Return -5 if the Messenger friend connection fails to initialize.
|
||||
*/
|
||||
non_null()
|
||||
int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state, const uint8_t *group_name,
|
||||
uint16_t group_name_length,
|
||||
const uint8_t *nick, size_t nick_length);
|
||||
|
||||
/** @brief Joins a group designated by `chat_id`.
|
||||
*
|
||||
* This function creates a new GC_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 the group is not password protected password should be set to NULL and password_length should be 0.
|
||||
*
|
||||
* Return group_number on success.
|
||||
* Return -1 if the group object fails to initialize.
|
||||
* Return -2 if chat_id is NULL or a group with chat_id already exists in the chats array.
|
||||
* Return -3 if nick is too long.
|
||||
* Return -4 if nick is empty or nick length is zero.
|
||||
* Return -5 if there is an error setting the group password.
|
||||
* Return -6 if the Messenger friend connection fails to initialize.
|
||||
*/
|
||||
non_null(1, 2, 3) nullable(5)
|
||||
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);
|
||||
|
||||
/** @brief Disconnects from all peers in a group but saves the group state for later use.
|
||||
*
|
||||
* Return true on sucess.
|
||||
* Return false if the group handler object or chat object is null.
|
||||
*/
|
||||
non_null()
|
||||
bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat);
|
||||
|
||||
/** @brief Disconnects from all peers in a group and attempts to reconnect.
|
||||
*
|
||||
* All self state and credentials are retained.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* 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);
|
||||
|
||||
/** @brief Joins a group using the invite data received in a friend's group invite.
|
||||
*
|
||||
* The invite is only valid while the inviter is present in the group.
|
||||
*
|
||||
* Return group_number on success.
|
||||
* Return -1 if the invite data is malformed.
|
||||
* Return -2 if the group object fails to initialize.
|
||||
* Return -3 if nick is too long.
|
||||
* Return -4 if nick is empty or nick length is zero.
|
||||
* Return -5 if there is an error setting the password.
|
||||
* Return -6 if friend doesn't exist.
|
||||
* Return -7 if sending packet failed.
|
||||
*/
|
||||
non_null(1, 3, 5) nullable(7)
|
||||
int gc_accept_invite(GC_Session *c, int32_t friend_number, const uint8_t *data, uint16_t length, const uint8_t *nick,
|
||||
size_t nick_length, const uint8_t *passwd, uint16_t passwd_len);
|
||||
|
||||
typedef bool gc_send_group_invite_packet_cb(const Messenger *m, uint32_t friendnumber, const uint8_t *packet,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Invites friend designated by `friendnumber` to chat.
|
||||
* Packet includes: Type, chat_id, TCP node or packed IP_Port.
|
||||
*
|
||||
* Return 0 on success.
|
||||
* Return -1 if friendnumber does not exist.
|
||||
* Return -2 on failure to create the invite data.
|
||||
* Return -3 if the packet fails to send.
|
||||
*/
|
||||
non_null()
|
||||
int gc_invite_friend(const GC_Session *c, GC_Chat *chat, int32_t friend_number,
|
||||
gc_send_group_invite_packet_cb *callback);
|
||||
|
||||
/** @brief Leaves a group and sends an exit broadcast packet with an optional parting message.
|
||||
*
|
||||
* All group state is permanently lost, including keys and roles.
|
||||
*
|
||||
* Return 0 on success.
|
||||
* Return -1 if the parting message is too long.
|
||||
* Return -2 if the parting message failed to send.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
int gc_group_exit(GC_Session *c, GC_Chat *chat, const uint8_t *message, uint16_t length);
|
||||
|
||||
/** @brief Returns true if `chat` is a valid group chat.
|
||||
*
|
||||
* A valid group chat constitutes an initialized chat instance with a non-zero shared state version.
|
||||
* The shared state version will be non-zero either if a peer has created the group, or if
|
||||
* they have ever successfully connected to the group.
|
||||
*/
|
||||
non_null()
|
||||
bool gc_group_is_valid(const GC_Chat *chat);
|
||||
|
||||
/** @brief Returns the number of active groups in `c`. */
|
||||
non_null()
|
||||
uint32_t gc_count_groups(const GC_Session *c);
|
||||
|
||||
/** @brief Returns true if peer_number exists */
|
||||
non_null()
|
||||
bool gc_peer_number_is_valid(const GC_Chat *chat, int peer_number);
|
||||
|
||||
/** @brief Return group_number's GC_Chat pointer on success
|
||||
* Return NULL on failure
|
||||
*/
|
||||
non_null()
|
||||
GC_Chat *gc_get_group(const GC_Session *c, int group_number);
|
||||
|
||||
/** @brief Sends a lossy message acknowledgement to peer associated with `gconn`.
|
||||
*
|
||||
* If `type` is GR_ACK_RECV we send a read-receipt for read_id's packet. If `type` is GR_ACK_REQ
|
||||
* we send a request for the respective id's packet.
|
||||
*
|
||||
* Requests are limited to one per second per peer.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool gc_send_message_ack(const GC_Chat *chat, GC_Connection *gconn, uint64_t message_id, Group_Message_Ack_Type type);
|
||||
|
||||
/** @brief Helper function for `handle_gc_lossless_packet()`.
|
||||
*
|
||||
* Note: This function may modify the peer list and change peer numbers.
|
||||
*
|
||||
* @retval true if packet is successfully handled.
|
||||
*/
|
||||
non_null(1, 2) nullable(4, 7)
|
||||
bool handle_gc_lossless_helper(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type, void *userdata);
|
||||
|
||||
/** @brief Handles an invite accept packet.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool handle_gc_invite_accepted_packet(const GC_Session *c, int friend_number, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief Return true if `chat_id` is not present in our group sessions array.
|
||||
*
|
||||
* `length` must be at least CHAT_ID_SIZE bytes in length.
|
||||
*/
|
||||
non_null()
|
||||
bool group_not_added(const GC_Session *c, const uint8_t *chat_id, uint32_t length);
|
||||
|
||||
/** @brief Handles an invite confirmed packet.
|
||||
*
|
||||
* Return 0 on success.
|
||||
* Return -1 if length is invalid.
|
||||
* Return -2 if data contains invalid chat_id.
|
||||
* Return -3 if data contains invalid peer info.
|
||||
* Return -4 if `friend_number` does not designate a valid friend.
|
||||
* Return -5 if data contains invalid connection info.
|
||||
*/
|
||||
non_null()
|
||||
int handle_gc_invite_confirmed_packet(const GC_Session *c, int friend_number, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief Returns the group designated by `public_key`.
|
||||
* Returns null if group does not exist.
|
||||
*/
|
||||
non_null()
|
||||
GC_Chat *gc_get_group_by_public_key(const GC_Session *c, const uint8_t *public_key);
|
||||
|
||||
/** @brief Attempts to add peers from `announces` to our peer list and initiate an invite request.
|
||||
*
|
||||
* Returns the number of peers added on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int gc_add_peers_from_announces(GC_Chat *chat, const GC_Announce *announces, uint8_t gc_announces_count);
|
||||
|
||||
#endif // GROUP_CHATS_H
|
409
external/toxcore/c-toxcore/toxcore/group_common.h
vendored
Normal file
409
external/toxcore/c-toxcore/toxcore/group_common.h
vendored
Normal file
@ -0,0 +1,409 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2022 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common groupchat data structures.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_COMMON_H
|
||||
#define GROUP_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "DHT.h"
|
||||
#include "TCP_connection.h"
|
||||
#include "group_moderation.h"
|
||||
|
||||
#define MAX_GC_PART_MESSAGE_SIZE 128
|
||||
#define MAX_GC_NICK_SIZE 128
|
||||
#define MAX_GC_TOPIC_SIZE 512
|
||||
#define MAX_GC_GROUP_NAME_SIZE 48
|
||||
#define GC_MESSAGE_PSEUDO_ID_SIZE 4
|
||||
#define GROUP_MAX_MESSAGE_LENGTH 1372
|
||||
|
||||
/* Max size of a packet chunk. Packets larger than this must be split up.
|
||||
*
|
||||
* For an explanation on why this value was chosen, see the following link: https://archive.ph/vsCOG
|
||||
*/
|
||||
#define MAX_GC_PACKET_CHUNK_SIZE 500
|
||||
|
||||
#define MAX_GC_MESSAGE_SIZE GROUP_MAX_MESSAGE_LENGTH
|
||||
#define MAX_GC_MESSAGE_RAW_SIZE (MAX_GC_MESSAGE_SIZE + GC_MESSAGE_PSEUDO_ID_SIZE)
|
||||
#define MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE 1373
|
||||
#define MAX_GC_CUSTOM_LOSSY_PACKET_SIZE MAX_GC_PACKET_CHUNK_SIZE
|
||||
#define MAX_GC_PASSWORD_SIZE 32
|
||||
#define MAX_GC_SAVED_INVITES 10
|
||||
#define MAX_GC_PEERS_DEFAULT 100
|
||||
#define MAX_GC_SAVED_TIMEOUTS 12
|
||||
#define GC_MAX_SAVED_PEERS 100
|
||||
#define GC_SAVED_PEER_SIZE (ENC_PUBLIC_KEY_SIZE + sizeof(Node_format) + sizeof(IP_Port))
|
||||
|
||||
/* Max size of a complete encrypted packet including headers. */
|
||||
#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
|
||||
|
||||
/** Self UDP status. Must correspond to return values from `ipport_self_copy()`. */
|
||||
typedef enum Self_UDP_Status {
|
||||
SELF_UDP_STATUS_NONE = 0x00,
|
||||
SELF_UDP_STATUS_WAN = 0x01,
|
||||
SELF_UDP_STATUS_LAN = 0x02,
|
||||
} Self_UDP_Status;
|
||||
|
||||
/** Group exit types. */
|
||||
typedef enum Group_Exit_Type {
|
||||
GC_EXIT_TYPE_QUIT = 0x00, // Peer left the group
|
||||
GC_EXIT_TYPE_TIMEOUT = 0x01, // Peer connection timed out
|
||||
GC_EXIT_TYPE_DISCONNECTED = 0x02, // Peer diconnected from group
|
||||
GC_EXIT_TYPE_SELF_DISCONNECTED = 0x03, // Self disconnected from group
|
||||
GC_EXIT_TYPE_KICKED = 0x04, // Peer was kicked from the group
|
||||
GC_EXIT_TYPE_SYNC_ERR = 0x05, // Peer failed to sync with the group
|
||||
GC_EXIT_TYPE_NO_CALLBACK = 0x06, // The peer exit callback should not be triggered
|
||||
} Group_Exit_Type;
|
||||
|
||||
typedef struct GC_Exit_Info {
|
||||
uint8_t part_message[MAX_GC_PART_MESSAGE_SIZE];
|
||||
uint16_t length;
|
||||
Group_Exit_Type exit_type;
|
||||
} GC_Exit_Info;
|
||||
|
||||
typedef struct GC_PeerAddress {
|
||||
uint8_t public_key[EXT_PUBLIC_KEY_SIZE];
|
||||
IP_Port ip_port;
|
||||
} GC_PeerAddress;
|
||||
|
||||
typedef struct GC_Message_Array_Entry {
|
||||
uint8_t *data;
|
||||
uint16_t data_length;
|
||||
uint8_t packet_type;
|
||||
uint64_t message_id;
|
||||
uint64_t time_added;
|
||||
uint64_t last_send_try;
|
||||
} GC_Message_Array_Entry;
|
||||
|
||||
typedef struct GC_Connection {
|
||||
uint64_t send_message_id; /* message_id of the next message we send to peer */
|
||||
|
||||
uint16_t send_array_start; /* send_array index of oldest item */
|
||||
GC_Message_Array_Entry *send_array;
|
||||
|
||||
uint64_t received_message_id; /* message_id of peer's last message to us */
|
||||
GC_Message_Array_Entry *recv_array;
|
||||
|
||||
uint64_t last_chunk_id; /* The message ID of the last packet fragment we received */
|
||||
|
||||
GC_PeerAddress addr; /* holds peer's extended real public key and ip_port */
|
||||
uint32_t public_key_hash; /* Jenkins one at a time hash of peer's real encryption public key */
|
||||
|
||||
uint8_t session_public_key[ENC_PUBLIC_KEY_SIZE]; /* self session public key for this peer */
|
||||
uint8_t session_secret_key[ENC_SECRET_KEY_SIZE]; /* self session secret key for this peer */
|
||||
uint8_t session_shared_key[CRYPTO_SHARED_KEY_SIZE]; /* made with our session sk and peer's session pk */
|
||||
|
||||
int tcp_connection_num;
|
||||
uint64_t last_sent_tcp_relays_time; /* the last time we attempted to send this peer our tcp relays */
|
||||
uint16_t tcp_relay_share_index;
|
||||
uint64_t last_received_direct_time; /* the last time we received a direct UDP packet from this connection */
|
||||
uint64_t last_sent_ip_time; /* the last time we sent our ip info to this peer in a ping packet */
|
||||
|
||||
Node_format connected_tcp_relays[MAX_FRIEND_TCP_CONNECTIONS];
|
||||
uint16_t tcp_relays_count;
|
||||
|
||||
uint64_t last_received_packet_time; /* The last time we successfully processed any packet from this peer */
|
||||
uint64_t last_requested_packet_time; /* The last time we requested a missing packet from this peer */
|
||||
uint64_t last_sent_ping_time;
|
||||
uint64_t last_sync_response; /* the last time we sent this peer a sync response */
|
||||
uint8_t oob_relay_pk[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
bool self_is_closer; /* true if we're "closer" to the chat_id than this peer (uses real pk's) */
|
||||
|
||||
bool confirmed; /* true if this peer has given us their info */
|
||||
bool handshaked; /* true if we've successfully handshaked with this peer */
|
||||
uint16_t handshake_attempts;
|
||||
uint64_t last_handshake_request;
|
||||
uint64_t last_handshake_response;
|
||||
uint8_t pending_handshake_type;
|
||||
bool is_pending_handshake_response;
|
||||
bool is_oob_handshake;
|
||||
|
||||
uint64_t last_key_rotation; /* the last time we rotated session keys for this peer */
|
||||
bool pending_key_rotation_request;
|
||||
|
||||
bool pending_delete; /* true if this peer has been marked for deletion */
|
||||
GC_Exit_Info exit_info;
|
||||
} GC_Connection;
|
||||
|
||||
/***
|
||||
* Group roles. Roles are hierarchical in that each role has a set of privileges plus
|
||||
* all the privileges of the roles below it.
|
||||
*/
|
||||
typedef enum Group_Role {
|
||||
/** Group creator. All-powerful. Cannot be demoted or kicked. */
|
||||
GR_FOUNDER = 0x00,
|
||||
|
||||
/**
|
||||
* May promote or demote peers below them to any role below them.
|
||||
* May also kick peers below them and set the topic.
|
||||
*/
|
||||
GR_MODERATOR = 0x01,
|
||||
|
||||
/** may interact normally with the group. */
|
||||
GR_USER = 0x02,
|
||||
|
||||
/** May not interact with the group but may observe. */
|
||||
GR_OBSERVER = 0x03,
|
||||
} Group_Role;
|
||||
|
||||
typedef enum Group_Peer_Status {
|
||||
GS_NONE = 0x00,
|
||||
GS_AWAY = 0x01,
|
||||
GS_BUSY = 0x02,
|
||||
} Group_Peer_Status;
|
||||
|
||||
/**
|
||||
* Group voice states. The state determines which Group Roles have permission to speak.
|
||||
*/
|
||||
typedef enum Group_Voice_State {
|
||||
/** Every group role except Observers may speak. */
|
||||
GV_ALL = 0x00,
|
||||
|
||||
/** Only Moderators and the Founder may speak. */
|
||||
GV_MODS = 0x01,
|
||||
|
||||
/** Only the Founder may speak. */
|
||||
GV_FOUNDER = 0x02,
|
||||
} Group_Voice_State;
|
||||
|
||||
/** Group connection states. */
|
||||
typedef enum GC_Conn_State {
|
||||
CS_NONE = 0x00, // Indicates a group is not initialized
|
||||
CS_DISCONNECTED = 0x01, // Not receiving or sending any packets
|
||||
CS_CONNECTING = 0x02, // Attempting to establish a connection with peers in the group
|
||||
CS_CONNECTED = 0x03, // Has successfully received a sync response from a peer in the group
|
||||
} GC_Conn_State;
|
||||
|
||||
/** Group privacy states. */
|
||||
typedef enum Group_Privacy_State {
|
||||
GI_PUBLIC = 0x00, // Anyone with the chat ID may join the group
|
||||
GI_PRIVATE = 0x01, // Peers may only join the group via a friend invite
|
||||
} Group_Privacy_State;
|
||||
|
||||
/** Handshake join types. */
|
||||
typedef enum Group_Handshake_Join_Type {
|
||||
HJ_PUBLIC = 0x00, // Indicates the group was joined via the DHT
|
||||
HJ_PRIVATE = 0x01, // Indicates the group was joined via private friend invite
|
||||
} Group_Handshake_Join_Type;
|
||||
|
||||
typedef struct GC_SavedPeerInfo {
|
||||
uint8_t public_key[ENC_PUBLIC_KEY_SIZE];
|
||||
Node_format tcp_relay;
|
||||
IP_Port ip_port;
|
||||
} GC_SavedPeerInfo;
|
||||
|
||||
/** Holds info about peers who recently timed out */
|
||||
typedef struct GC_TimedOutPeer {
|
||||
GC_SavedPeerInfo addr;
|
||||
uint64_t last_seen; // the time the peer disconnected
|
||||
uint64_t last_reconn_try; // the last time we tried to establish a new connection
|
||||
} GC_TimedOutPeer;
|
||||
|
||||
typedef struct GC_Peer {
|
||||
/* Below state is sent to other peers in peer info exchange */
|
||||
uint8_t nick[MAX_GC_NICK_SIZE];
|
||||
uint16_t nick_length;
|
||||
uint8_t status;
|
||||
|
||||
/* Below state is local only */
|
||||
Group_Role role;
|
||||
uint32_t peer_id; // permanent ID (used for the public API)
|
||||
bool ignore;
|
||||
|
||||
GC_Connection gconn;
|
||||
} GC_Peer;
|
||||
|
||||
typedef struct GC_SharedState {
|
||||
uint32_t version;
|
||||
uint8_t founder_public_key[EXT_PUBLIC_KEY_SIZE];
|
||||
uint16_t maxpeers;
|
||||
uint16_t group_name_len;
|
||||
uint8_t group_name[MAX_GC_GROUP_NAME_SIZE];
|
||||
Group_Privacy_State privacy_state; // GI_PUBLIC (uses DHT) or GI_PRIVATE (invite only)
|
||||
uint16_t password_length;
|
||||
uint8_t password[MAX_GC_PASSWORD_SIZE];
|
||||
uint8_t mod_list_hash[MOD_MODERATION_HASH_SIZE];
|
||||
uint32_t topic_lock; // equal to GC_TOPIC_LOCK_ENABLED when lock is enabled
|
||||
Group_Voice_State voice_state;
|
||||
} GC_SharedState;
|
||||
|
||||
typedef struct GC_TopicInfo {
|
||||
uint32_t version;
|
||||
uint16_t length;
|
||||
uint16_t checksum; // used for syncing problems. the checksum with the highest value gets priority.
|
||||
uint8_t topic[MAX_GC_TOPIC_SIZE];
|
||||
uint8_t public_sig_key[SIG_PUBLIC_KEY_SIZE]; // Public signature key of the topic setter
|
||||
} GC_TopicInfo;
|
||||
|
||||
typedef struct GC_Chat {
|
||||
Mono_Time *mono_time;
|
||||
const Logger *log;
|
||||
const Random *rng;
|
||||
|
||||
uint32_t connected_tcp_relays;
|
||||
Self_UDP_Status self_udp_status;
|
||||
IP_Port self_ip_port;
|
||||
|
||||
Networking_Core *net;
|
||||
TCP_Connections *tcp_conn;
|
||||
|
||||
uint64_t last_checked_tcp_relays;
|
||||
Group_Handshake_Join_Type join_type;
|
||||
|
||||
GC_Peer *group;
|
||||
Moderation moderation;
|
||||
|
||||
GC_Conn_State connection_state;
|
||||
|
||||
GC_SharedState shared_state;
|
||||
uint8_t shared_state_sig[SIGNATURE_SIZE]; // signed by founder using the chat secret key
|
||||
|
||||
GC_TopicInfo topic_info;
|
||||
uint8_t topic_sig[SIGNATURE_SIZE]; // signed by the peer who set the current topic
|
||||
uint16_t topic_prev_checksum; // checksum of the previous topic
|
||||
uint64_t topic_time_set;
|
||||
|
||||
uint16_t peers_checksum; // sum of the public key hash of every confirmed peer in the group
|
||||
uint16_t roles_checksum; // sum of every confirmed peer's role plus the first byte of their public key
|
||||
|
||||
uint32_t numpeers;
|
||||
int group_number;
|
||||
|
||||
uint8_t chat_public_key[EXT_PUBLIC_KEY_SIZE]; // the chat_id is the sig portion
|
||||
uint8_t chat_secret_key[EXT_SECRET_KEY_SIZE]; // only used by the founder
|
||||
|
||||
uint8_t self_public_key[EXT_PUBLIC_KEY_SIZE];
|
||||
uint8_t self_secret_key[EXT_SECRET_KEY_SIZE];
|
||||
|
||||
uint64_t time_connected;
|
||||
uint64_t last_ping_interval;
|
||||
uint64_t last_sync_request; // The last time we sent a sync request to any peer
|
||||
uint64_t last_sync_response_peer_list; // The last time we sent the peer list to any peer
|
||||
uint64_t last_time_peers_loaded;
|
||||
|
||||
/* keeps track of frequency of new inbound connections */
|
||||
uint8_t connection_O_metre;
|
||||
uint64_t connection_cooldown_timer;
|
||||
bool block_handshakes;
|
||||
|
||||
int32_t saved_invites[MAX_GC_SAVED_INVITES];
|
||||
uint8_t saved_invites_index;
|
||||
|
||||
/** A list of recently seen peers in case we disconnect from a private group.
|
||||
* Peers are added once they're confirmed, and only if there are vacant
|
||||
* spots (older connections get priority). An entry is removed only when the list
|
||||
* is full, its respective peer goes offline, and an online peer who isn't yet
|
||||
* present in the list can be added.
|
||||
*/
|
||||
GC_SavedPeerInfo saved_peers[GC_MAX_SAVED_PEERS];
|
||||
|
||||
GC_TimedOutPeer timeout_list[MAX_GC_SAVED_TIMEOUTS];
|
||||
size_t timeout_list_index;
|
||||
uint64_t last_timed_out_reconn_try; // the last time we tried to reconnect to timed out peers
|
||||
|
||||
bool update_self_announces; // true if we should try to update our announcements
|
||||
uint64_t last_self_announce_check; // the last time we checked if we should update our announcements
|
||||
uint64_t last_time_self_announce; // the last time we announced the group
|
||||
uint8_t announced_tcp_relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; // The pk of the last TCP relay we announced
|
||||
|
||||
uint8_t m_group_public_key[CRYPTO_PUBLIC_KEY_SIZE]; // public key for group's messenger friend connection
|
||||
int friend_connection_id; // identifier for group's messenger friend connection
|
||||
} GC_Chat;
|
||||
|
||||
#ifndef MESSENGER_DEFINED
|
||||
#define MESSENGER_DEFINED
|
||||
typedef struct Messenger Messenger;
|
||||
#endif /* MESSENGER_DEFINED */
|
||||
|
||||
typedef void gc_message_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int type,
|
||||
const uint8_t *data, size_t length, uint32_t message_id, void *user_data);
|
||||
typedef void gc_private_message_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int type,
|
||||
const uint8_t *data, size_t length, void *user_data);
|
||||
typedef void gc_custom_packet_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void gc_custom_private_packet_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id,
|
||||
const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void gc_moderation_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, uint32_t target_peer,
|
||||
unsigned int mod_event, void *user_data);
|
||||
typedef void gc_nick_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void gc_status_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int status,
|
||||
void *user_data);
|
||||
typedef void gc_topic_change_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void gc_topic_lock_cb(const Messenger *m, uint32_t group_number, unsigned int topic_lock, void *user_data);
|
||||
typedef void gc_voice_state_cb(const Messenger *m, uint32_t group_number, unsigned int voice_state, void *user_data);
|
||||
typedef void gc_peer_limit_cb(const Messenger *m, uint32_t group_number, uint32_t max_peers, void *user_data);
|
||||
typedef void gc_privacy_state_cb(const Messenger *m, uint32_t group_number, unsigned int state, void *user_data);
|
||||
typedef void gc_password_cb(const Messenger *m, uint32_t group_number, const uint8_t *data, size_t length,
|
||||
void *user_data);
|
||||
typedef void gc_peer_join_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, void *user_data);
|
||||
typedef void gc_peer_exit_cb(const Messenger *m, uint32_t group_number, uint32_t peer_id, unsigned int exit_type,
|
||||
const uint8_t *nick, size_t nick_len, const uint8_t *data, size_t length, void *user_data);
|
||||
typedef void gc_self_join_cb(const Messenger *m, uint32_t group_number, void *user_data);
|
||||
typedef void gc_rejected_cb(const Messenger *m, uint32_t group_number, unsigned int type, void *user_data);
|
||||
|
||||
typedef struct GC_Session {
|
||||
Messenger *messenger;
|
||||
GC_Chat *chats;
|
||||
struct GC_Announces_List *announces_list;
|
||||
|
||||
uint32_t chats_index;
|
||||
|
||||
gc_message_cb *message;
|
||||
gc_private_message_cb *private_message;
|
||||
gc_custom_packet_cb *custom_packet;
|
||||
gc_custom_private_packet_cb *custom_private_packet;
|
||||
gc_moderation_cb *moderation;
|
||||
gc_nick_change_cb *nick_change;
|
||||
gc_status_change_cb *status_change;
|
||||
gc_topic_change_cb *topic_change;
|
||||
gc_topic_lock_cb *topic_lock;
|
||||
gc_voice_state_cb *voice_state;
|
||||
gc_peer_limit_cb *peer_limit;
|
||||
gc_privacy_state_cb *privacy_state;
|
||||
gc_password_cb *password;
|
||||
gc_peer_join_cb *peer_join;
|
||||
gc_peer_exit_cb *peer_exit;
|
||||
gc_self_join_cb *self_join;
|
||||
gc_rejected_cb *rejected;
|
||||
} GC_Session;
|
||||
|
||||
/** @brief Adds a new peer to group_number's peer list.
|
||||
*
|
||||
* Return peer_number on success.
|
||||
* Return -1 on failure.
|
||||
* Return -2 if a peer with public_key is already in our peerlist.
|
||||
*/
|
||||
non_null(1, 3) nullable(2)
|
||||
int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key);
|
||||
|
||||
/** @brief Unpacks saved peers from `data` of size `length` into `chat`.
|
||||
*
|
||||
* Returns the number of unpacked peers on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int unpack_gc_saved_peers(GC_Chat *chat, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief Packs all valid entries from saved peerlist into `data`.
|
||||
*
|
||||
* If `processed` is non-null it will be set to the length of the packed data.
|
||||
*
|
||||
* Return the number of packed saved peers on success.
|
||||
* Return -1 if buffer is too small.
|
||||
*/
|
||||
non_null(1, 2) nullable(4)
|
||||
int pack_gc_saved_peers(const GC_Chat *chat, uint8_t *data, uint16_t length, uint16_t *processed);
|
||||
|
||||
#endif // GROUP_COMMON_H
|
707
external/toxcore/c-toxcore/toxcore/group_connection.c
vendored
Normal file
707
external/toxcore/c-toxcore/toxcore/group_connection.c
vendored
Normal file
@ -0,0 +1,707 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of massive text only group chats.
|
||||
*/
|
||||
|
||||
#include "group_connection.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "DHT.h"
|
||||
#include "ccompat.h"
|
||||
#include "crypto_core.h"
|
||||
#include "group_chats.h"
|
||||
#include "group_common.h"
|
||||
#include "mono_time.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
|
||||
/** Seconds since last direct UDP packet was received before the connection is considered dead */
|
||||
#define GCC_UDP_DIRECT_TIMEOUT (GC_PING_TIMEOUT + 4)
|
||||
|
||||
/** Returns true if array entry does not contain an active packet. */
|
||||
non_null()
|
||||
static bool array_entry_is_empty(const GC_Message_Array_Entry *array_entry)
|
||||
{
|
||||
assert(array_entry != nullptr);
|
||||
return array_entry->time_added == 0;
|
||||
}
|
||||
|
||||
/** @brief Clears an array entry. */
|
||||
non_null()
|
||||
static void clear_array_entry(GC_Message_Array_Entry *const array_entry)
|
||||
{
|
||||
if (array_entry->data != nullptr) {
|
||||
free(array_entry->data);
|
||||
}
|
||||
|
||||
*array_entry = (GC_Message_Array_Entry) {
|
||||
nullptr
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears every send array message from queue starting at the index designated by
|
||||
* `start_id` and ending at `end_id`, and sets the send_message_id for `gconn`
|
||||
* to `start_id`.
|
||||
*/
|
||||
non_null()
|
||||
static void clear_send_queue_id_range(GC_Connection *gconn, uint64_t start_id, uint64_t end_id)
|
||||
{
|
||||
const uint16_t start_idx = gcc_get_array_index(start_id);
|
||||
const uint16_t end_idx = gcc_get_array_index(end_id);
|
||||
|
||||
for (uint16_t i = start_idx; i != end_idx; i = (i + 1) % GCC_BUFFER_SIZE) {
|
||||
GC_Message_Array_Entry *entry = &gconn->send_array[i];
|
||||
clear_array_entry(entry);
|
||||
}
|
||||
|
||||
gconn->send_message_id = start_id;
|
||||
}
|
||||
|
||||
uint16_t gcc_get_array_index(uint64_t message_id)
|
||||
{
|
||||
return message_id % GCC_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
void gcc_set_send_message_id(GC_Connection *gconn, uint64_t id)
|
||||
{
|
||||
gconn->send_message_id = id;
|
||||
gconn->send_array_start = id % GCC_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
void gcc_set_recv_message_id(GC_Connection *gconn, uint64_t id)
|
||||
{
|
||||
gconn->received_message_id = id;
|
||||
}
|
||||
|
||||
/** @brief Puts packet data in array_entry.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
static bool create_array_entry(const Mono_Time *mono_time, GC_Message_Array_Entry *array_entry, const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type, uint64_t message_id)
|
||||
{
|
||||
if (length > 0) {
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
array_entry->data = (uint8_t *)malloc(sizeof(uint8_t) * length);
|
||||
|
||||
if (array_entry->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(array_entry->data, data, length);
|
||||
}
|
||||
|
||||
const uint64_t tm = mono_time_get(mono_time);
|
||||
|
||||
array_entry->data_length = length;
|
||||
array_entry->packet_type = packet_type;
|
||||
array_entry->message_id = message_id;
|
||||
array_entry->time_added = tm;
|
||||
array_entry->last_send_try = tm;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Adds data of length to gconn's send_array.
|
||||
*
|
||||
* Returns true on success and increments gconn's send_message_id.
|
||||
*/
|
||||
non_null(1, 2, 3) nullable(4)
|
||||
static bool add_to_send_array(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn, const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type)
|
||||
{
|
||||
/* check if send_array is full */
|
||||
if ((gconn->send_message_id % GCC_BUFFER_SIZE) == (uint16_t)(gconn->send_array_start - 1)) {
|
||||
LOGGER_DEBUG(log, "Send array overflow");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t idx = gcc_get_array_index(gconn->send_message_id);
|
||||
GC_Message_Array_Entry *array_entry = &gconn->send_array[idx];
|
||||
|
||||
if (!array_entry_is_empty(array_entry)) {
|
||||
LOGGER_DEBUG(log, "Send array entry isn't empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create_array_entry(mono_time, array_entry, data, length, packet_type, gconn->send_message_id)) {
|
||||
LOGGER_WARNING(log, "Failed to create array entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
++gconn->send_message_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int gcc_send_lossless_packet(const GC_Chat *chat, GC_Connection *gconn, const uint8_t *data, uint16_t length,
|
||||
uint8_t packet_type)
|
||||
{
|
||||
const uint64_t message_id = gconn->send_message_id;
|
||||
|
||||
if (!add_to_send_array(chat->log, chat->mono_time, gconn, data, length, packet_type)) {
|
||||
LOGGER_WARNING(chat->log, "Failed to add payload to send array: (type: 0x%02x, length: %d)", packet_type, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!gcc_encrypt_and_send_lossless_packet(chat, gconn, data, length, message_id, packet_type)) {
|
||||
LOGGER_DEBUG(chat->log, "Failed to send payload: (type: 0x%02x, length: %d)", packet_type, length);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool gcc_send_lossless_packet_fragments(const GC_Chat *chat, GC_Connection *gconn, const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type)
|
||||
{
|
||||
if (length <= MAX_GC_PACKET_CHUNK_SIZE || data == nullptr) {
|
||||
LOGGER_FATAL(chat->log, "invalid length or null data pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t start_id = gconn->send_message_id;
|
||||
|
||||
// First packet segment is comprised of packet type + first chunk of payload
|
||||
uint8_t chunk[MAX_GC_PACKET_CHUNK_SIZE];
|
||||
chunk[0] = packet_type;
|
||||
memcpy(chunk + 1, data, MAX_GC_PACKET_CHUNK_SIZE - 1);
|
||||
|
||||
if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, MAX_GC_PACKET_CHUNK_SIZE, GP_FRAGMENT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t processed = MAX_GC_PACKET_CHUNK_SIZE - 1;
|
||||
|
||||
// The rest of the segments are added in chunks
|
||||
while (length > processed) {
|
||||
const uint16_t chunk_len = min_u16(MAX_GC_PACKET_CHUNK_SIZE, length - processed);
|
||||
|
||||
memcpy(chunk, data + processed, chunk_len);
|
||||
processed += chunk_len;
|
||||
|
||||
if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, chunk_len, GP_FRAGMENT)) {
|
||||
clear_send_queue_id_range(gconn, start_id, gconn->send_message_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// empty packet signals the end of the sequence
|
||||
if (!add_to_send_array(chat->log, chat->mono_time, gconn, nullptr, 0, GP_FRAGMENT)) {
|
||||
clear_send_queue_id_range(gconn, start_id, gconn->send_message_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t start_idx = gcc_get_array_index(start_id);
|
||||
const uint16_t end_idx = gcc_get_array_index(gconn->send_message_id);
|
||||
|
||||
for (uint16_t i = start_idx; i != end_idx; i = (i + 1) % GCC_BUFFER_SIZE) {
|
||||
GC_Message_Array_Entry *entry = &gconn->send_array[i];
|
||||
|
||||
if (array_entry_is_empty(entry)) {
|
||||
LOGGER_FATAL(chat->log, "array entry for packet chunk is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(entry->packet_type == GP_FRAGMENT);
|
||||
|
||||
gcc_encrypt_and_send_lossless_packet(chat, gconn, entry->data, entry->data_length,
|
||||
entry->message_id, entry->packet_type);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id)
|
||||
{
|
||||
uint16_t idx = gcc_get_array_index(message_id);
|
||||
GC_Message_Array_Entry *array_entry = &gconn->send_array[idx];
|
||||
|
||||
if (array_entry_is_empty(array_entry)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array_entry->message_id != message_id) { // wrap-around indicates a connection problem
|
||||
LOGGER_DEBUG(log, "Wrap-around on message %llu", (unsigned long long)message_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
clear_array_entry(array_entry);
|
||||
|
||||
/* Put send_array_start in proper position */
|
||||
if (idx == gconn->send_array_start) {
|
||||
const uint16_t end = gconn->send_message_id % GCC_BUFFER_SIZE;
|
||||
|
||||
while (array_entry_is_empty(&gconn->send_array[idx]) && gconn->send_array_start != end) {
|
||||
gconn->send_array_start = (gconn->send_array_start + 1) % GCC_BUFFER_SIZE;
|
||||
idx = (idx + 1) % GCC_BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gcc_ip_port_is_set(const GC_Connection *gconn)
|
||||
{
|
||||
return ipport_isset(&gconn->addr.ip_port);
|
||||
}
|
||||
|
||||
void gcc_set_ip_port(GC_Connection *gconn, const IP_Port *ipp)
|
||||
{
|
||||
if (ipp != nullptr && ipport_isset(ipp)) {
|
||||
gconn->addr.ip_port = *ipp;
|
||||
}
|
||||
}
|
||||
|
||||
bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Connection *gconn)
|
||||
{
|
||||
if (gconn == nullptr || tcp_node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gconn->tcp_relays_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t rand_idx = random_range_u32(rng, gconn->tcp_relays_count);
|
||||
|
||||
if (!ipport_isset(&gconn->connected_tcp_relays[rand_idx].ip_port)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*tcp_node = gconn->connected_tcp_relays[rand_idx];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int gcc_save_tcp_relay(const Random *rng, GC_Connection *gconn, const Node_format *tcp_node)
|
||||
{
|
||||
if (gconn == nullptr || tcp_node == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ipport_isset(&tcp_node->ip_port)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < gconn->tcp_relays_count; ++i) {
|
||||
if (pk_equal(gconn->connected_tcp_relays[i].public_key, tcp_node->public_key)) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t idx = gconn->tcp_relays_count;
|
||||
|
||||
if (gconn->tcp_relays_count >= MAX_FRIEND_TCP_CONNECTIONS) {
|
||||
idx = random_range_u32(rng, gconn->tcp_relays_count);
|
||||
} else {
|
||||
++gconn->tcp_relays_count;
|
||||
}
|
||||
|
||||
gconn->connected_tcp_relays[idx] = *tcp_node;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Stores `data` of length `length` in the receive array for `gconn`.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null(1, 2, 3) nullable(4)
|
||||
static bool store_in_recv_array(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
|
||||
const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type, uint64_t message_id)
|
||||
{
|
||||
const uint16_t idx = gcc_get_array_index(message_id);
|
||||
GC_Message_Array_Entry *ary_entry = &gconn->recv_array[idx];
|
||||
|
||||
if (!array_entry_is_empty(ary_entry)) {
|
||||
LOGGER_DEBUG(log, "Recv array is not empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create_array_entry(mono_time, ary_entry, data, length, packet_type, message_id)) {
|
||||
LOGGER_WARNING(log, "Failed to create array entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassembles a fragmented packet sequence ending with the data in the receive
|
||||
* array at slot `message_id - 1` and starting with the last found slot containing
|
||||
* a GP_FRAGMENT packet when searching backwards in the array.
|
||||
*
|
||||
* The fully reassembled packet is stored in `payload`, which must be passed as a
|
||||
* null pointer, and must be free'd by the caller.
|
||||
*
|
||||
* Return the length of the fully reassembled packet on success.
|
||||
* Return 0 on failure.
|
||||
*/
|
||||
non_null(1, 3) nullable(2)
|
||||
static uint16_t reassemble_packet(const Logger *log, GC_Connection *gconn, uint8_t **payload, uint64_t message_id)
|
||||
{
|
||||
uint16_t end_idx = gcc_get_array_index(message_id - 1);
|
||||
uint16_t start_idx = end_idx;
|
||||
uint16_t packet_length = 0;
|
||||
|
||||
GC_Message_Array_Entry *entry = &gconn->recv_array[end_idx];
|
||||
|
||||
// search backwards in recv array until we find an empty slot or a non-fragment packet type
|
||||
while (!array_entry_is_empty(entry) && entry->packet_type == GP_FRAGMENT) {
|
||||
assert(entry->data != nullptr);
|
||||
assert(entry->data_length <= MAX_GC_PACKET_CHUNK_SIZE);
|
||||
|
||||
const uint16_t diff = packet_length + entry->data_length;
|
||||
|
||||
assert(diff > packet_length); // overflow check
|
||||
packet_length = diff;
|
||||
|
||||
if (packet_length > MAX_GC_PACKET_SIZE) {
|
||||
LOGGER_ERROR(log, "Payload of size %u exceeded max packet size", packet_length); // should never happen
|
||||
return 0;
|
||||
}
|
||||
|
||||
start_idx = start_idx > 0 ? start_idx - 1 : GCC_BUFFER_SIZE - 1;
|
||||
entry = &gconn->recv_array[start_idx];
|
||||
|
||||
if (start_idx == end_idx) {
|
||||
LOGGER_ERROR(log, "Packet reassemble wrap-around");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(*payload == nullptr);
|
||||
*payload = (uint8_t *)malloc(packet_length);
|
||||
|
||||
if (*payload == nullptr) {
|
||||
LOGGER_ERROR(log, "Failed to allocate %u bytes for payload buffer", packet_length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
start_idx = (start_idx + 1) % GCC_BUFFER_SIZE;
|
||||
end_idx = (end_idx + 1) % GCC_BUFFER_SIZE;
|
||||
|
||||
uint16_t processed = 0;
|
||||
|
||||
for (uint16_t i = start_idx; i != end_idx; i = (i + 1) % GCC_BUFFER_SIZE) {
|
||||
entry = &gconn->recv_array[i];
|
||||
|
||||
assert(processed + entry->data_length <= packet_length);
|
||||
memcpy(*payload + processed, entry->data, entry->data_length);
|
||||
processed += entry->data_length;
|
||||
|
||||
clear_array_entry(entry);
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer_number,
|
||||
GC_Connection *gconn, const uint8_t *chunk, uint16_t length, uint8_t packet_type,
|
||||
uint64_t message_id, void *userdata)
|
||||
{
|
||||
if (length > 0) {
|
||||
if (!store_in_recv_array(chat->log, chat->mono_time, gconn, chunk, length, packet_type, message_id)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
|
||||
gconn->last_chunk_id = message_id;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t sender_pk[ENC_PUBLIC_KEY_SIZE];
|
||||
memcpy(sender_pk, get_enc_key(gconn->addr.public_key), ENC_PUBLIC_KEY_SIZE);
|
||||
|
||||
uint8_t *payload = nullptr;
|
||||
const uint16_t processed_len = reassemble_packet(chat->log, gconn, &payload, message_id);
|
||||
|
||||
if (processed_len == 0) {
|
||||
free(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!handle_gc_lossless_helper(c, chat, peer_number, payload + 1, processed_len - 1, payload[0], userdata)) {
|
||||
free(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* peer number can change from peer add operations in packet handlers */
|
||||
peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
|
||||
gconn = get_gc_connection(chat, peer_number);
|
||||
|
||||
if (gconn == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
|
||||
gconn->last_chunk_id = 0;
|
||||
|
||||
free(payload);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcc_handle_received_message(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
|
||||
const uint8_t *data, uint16_t length, uint8_t packet_type, uint64_t message_id,
|
||||
bool direct_conn)
|
||||
{
|
||||
if (direct_conn) {
|
||||
gconn->last_received_direct_time = mono_time_get(mono_time);
|
||||
}
|
||||
|
||||
/* Appears to be a duplicate packet so we discard it */
|
||||
if (message_id < gconn->received_message_id + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (packet_type == GP_FRAGMENT) { // we handle packet fragments as a special case
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* we're missing an older message from this peer so we store it in recv_array */
|
||||
if (message_id > gconn->received_message_id + 1) {
|
||||
if (!store_in_recv_array(log, mono_time, gconn, data, length, packet_type, message_id)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
/** @brief Handles peer_number's array entry with appropriate handler and clears it from array.
|
||||
*
|
||||
* This function increments the received message ID for `gconn`.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null(1, 2, 3, 5) nullable(6)
|
||||
static bool process_recv_array_entry(const GC_Session *c, GC_Chat *chat, GC_Connection *gconn, uint32_t peer_number,
|
||||
GC_Message_Array_Entry *const array_entry, void *userdata)
|
||||
{
|
||||
uint8_t sender_pk[ENC_PUBLIC_KEY_SIZE];
|
||||
memcpy(sender_pk, get_enc_key(gconn->addr.public_key), ENC_PUBLIC_KEY_SIZE);
|
||||
|
||||
const bool ret = handle_gc_lossless_helper(c, chat, peer_number, array_entry->data, array_entry->data_length,
|
||||
array_entry->packet_type, userdata);
|
||||
|
||||
/* peer number can change from peer add operations in packet handlers */
|
||||
peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
|
||||
gconn = get_gc_connection(chat, peer_number);
|
||||
|
||||
clear_array_entry(array_entry);
|
||||
|
||||
if (gconn == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
gc_send_message_ack(chat, gconn, array_entry->message_id, GR_ACK_REQ);
|
||||
return false;
|
||||
}
|
||||
|
||||
gc_send_message_ack(chat, gconn, array_entry->message_id, GR_ACK_RECV);
|
||||
|
||||
gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gcc_check_recv_array(const GC_Session *c, GC_Chat *chat, GC_Connection *gconn, uint32_t peer_number,
|
||||
void *userdata)
|
||||
{
|
||||
if (gconn->last_chunk_id != 0) { // dont check array if we have an unfinished fragment sequence
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t idx = (gconn->received_message_id + 1) % GCC_BUFFER_SIZE;
|
||||
GC_Message_Array_Entry *const array_entry = &gconn->recv_array[idx];
|
||||
|
||||
if (!array_entry_is_empty(array_entry)) {
|
||||
process_recv_array_entry(c, chat, gconn, peer_number, array_entry, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
void gcc_resend_packets(const GC_Chat *chat, GC_Connection *gconn)
|
||||
{
|
||||
const uint64_t tm = mono_time_get(chat->mono_time);
|
||||
const uint16_t start = gconn->send_array_start;
|
||||
const uint16_t end = gconn->send_message_id % GCC_BUFFER_SIZE;
|
||||
|
||||
GC_Message_Array_Entry *array_entry = &gconn->send_array[start];
|
||||
|
||||
if (array_entry_is_empty(array_entry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mono_time_is_timeout(chat->mono_time, array_entry->time_added, GC_CONFIRMED_PEER_TIMEOUT)) {
|
||||
gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_TIMEOUT, nullptr, 0);
|
||||
LOGGER_DEBUG(chat->log, "Send array stuck; timing out peer");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16_t i = start; i != end; i = (i + 1) % GCC_BUFFER_SIZE) {
|
||||
array_entry = &gconn->send_array[i];
|
||||
|
||||
if (array_entry_is_empty(array_entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tm == array_entry->last_send_try) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t delta = array_entry->last_send_try - array_entry->time_added;
|
||||
array_entry->last_send_try = tm;
|
||||
|
||||
/* if this occurrs less than once per second this won't be reliable */
|
||||
if (delta > 1 && is_power_of_2(delta)) {
|
||||
gcc_encrypt_and_send_lossless_packet(chat, gconn, array_entry->data, array_entry->data_length,
|
||||
array_entry->message_id, array_entry->packet_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool gcc_send_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *packet, uint16_t length)
|
||||
{
|
||||
if (packet == nullptr || length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool direct_send_attempt = false;
|
||||
|
||||
if (gcc_direct_conn_is_possible(chat, gconn)) {
|
||||
if (gcc_conn_is_direct(chat->mono_time, gconn)) {
|
||||
return (uint16_t) sendpacket(chat->net, &gconn->addr.ip_port, packet, length) == length;
|
||||
}
|
||||
|
||||
if ((uint16_t) sendpacket(chat->net, &gconn->addr.ip_port, packet, length) == length) {
|
||||
direct_send_attempt = true;
|
||||
}
|
||||
}
|
||||
|
||||
const int ret = send_packet_tcp_connection(chat->tcp_conn, gconn->tcp_connection_num, packet, length);
|
||||
return ret == 0 || direct_send_attempt;
|
||||
}
|
||||
|
||||
bool gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *data,
|
||||
uint16_t length, uint64_t message_id, uint8_t packet_type)
|
||||
{
|
||||
const uint16_t packet_size = gc_get_wrapped_packet_size(length, NET_PACKET_GC_LOSSLESS);
|
||||
uint8_t *packet = (uint8_t *)malloc(packet_size);
|
||||
|
||||
if (packet == nullptr) {
|
||||
LOGGER_ERROR(chat->log, "Failed to allocate memory for packet buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int enc_len = group_packet_wrap(
|
||||
chat->log, chat->rng, chat->self_public_key, gconn->session_shared_key, packet,
|
||||
packet_size, data, length, message_id, packet_type, NET_PACKET_GC_LOSSLESS);
|
||||
|
||||
if (enc_len < 0) {
|
||||
LOGGER_ERROR(chat->log, "Failed to wrap packet (type: 0x%02x, error: %d)", packet_type, enc_len);
|
||||
free(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gcc_send_packet(chat, gconn, packet, (uint16_t)enc_len)) {
|
||||
LOGGER_DEBUG(chat->log, "Failed to send packet (type: 0x%02x, enc_len: %d)", packet_type, enc_len);
|
||||
free(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gcc_make_session_shared_key(GC_Connection *gconn, const uint8_t *sender_pk)
|
||||
{
|
||||
encrypt_precompute(sender_pk, gconn->session_secret_key, gconn->session_shared_key);
|
||||
}
|
||||
|
||||
bool gcc_conn_is_direct(const Mono_Time *mono_time, const GC_Connection *gconn)
|
||||
{
|
||||
return GCC_UDP_DIRECT_TIMEOUT + gconn->last_received_direct_time > mono_time_get(mono_time);
|
||||
}
|
||||
|
||||
bool gcc_direct_conn_is_possible(const GC_Chat *chat, const GC_Connection *gconn)
|
||||
{
|
||||
return !net_family_is_unspec(gconn->addr.ip_port.ip.family) && !net_family_is_unspec(net_family(chat->net));
|
||||
}
|
||||
|
||||
void gcc_mark_for_deletion(GC_Connection *gconn, TCP_Connections *tcp_conn, Group_Exit_Type type,
|
||||
const uint8_t *part_message, uint16_t length)
|
||||
{
|
||||
if (gconn == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gconn->pending_delete) {
|
||||
return;
|
||||
}
|
||||
|
||||
gconn->pending_delete = true;
|
||||
gconn->exit_info.exit_type = type;
|
||||
|
||||
kill_tcp_connection_to(tcp_conn, gconn->tcp_connection_num);
|
||||
|
||||
if (length > 0 && length <= MAX_GC_PART_MESSAGE_SIZE && part_message != nullptr) {
|
||||
memcpy(gconn->exit_info.part_message, part_message, length);
|
||||
gconn->exit_info.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
void gcc_peer_cleanup(GC_Connection *gconn)
|
||||
{
|
||||
for (size_t i = 0; i < GCC_BUFFER_SIZE; ++i) {
|
||||
free(gconn->send_array[i].data);
|
||||
free(gconn->recv_array[i].data);
|
||||
}
|
||||
|
||||
free(gconn->recv_array);
|
||||
free(gconn->send_array);
|
||||
|
||||
crypto_memunlock(gconn->session_secret_key, sizeof(gconn->session_secret_key));
|
||||
crypto_memunlock(gconn->session_shared_key, sizeof(gconn->session_shared_key));
|
||||
crypto_memzero(gconn, sizeof(GC_Connection));
|
||||
}
|
||||
|
||||
void gcc_cleanup(const GC_Chat *chat)
|
||||
{
|
||||
for (uint32_t i = 0; i < chat->numpeers; ++i) {
|
||||
GC_Connection *gconn = get_gc_connection(chat, i);
|
||||
assert(gconn != nullptr);
|
||||
|
||||
gcc_peer_cleanup(gconn);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VANILLA_NACL
|
189
external/toxcore/c-toxcore/toxcore/group_connection.h
vendored
Normal file
189
external/toxcore/c-toxcore/toxcore/group_connection.h
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of massive text only group chats.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_CONNECTION_H
|
||||
#define GROUP_CONNECTION_H
|
||||
|
||||
#include "group_common.h"
|
||||
|
||||
/* Max number of TCP relays we share with a peer on handshake */
|
||||
#define GCC_MAX_TCP_SHARED_RELAYS 3
|
||||
|
||||
/** Marks a peer for deletion. If gconn is null or already marked for deletion this function has no effect. */
|
||||
non_null(1, 2) nullable(4)
|
||||
void gcc_mark_for_deletion(GC_Connection *gconn, TCP_Connections *tcp_conn, Group_Exit_Type type,
|
||||
const uint8_t *part_message, uint16_t length);
|
||||
|
||||
/** @brief Decides if message need to be put in recv_array or immediately handled.
|
||||
*
|
||||
* Return 3 if message is in correct sequence and is a fragment packet.
|
||||
* Return 2 if message is in correct sequence and may be handled immediately.
|
||||
* Return 1 if packet is out of sequence and added to recv_array.
|
||||
* Return 0 if message is a duplicate.
|
||||
* Return -1 on failure
|
||||
*/
|
||||
non_null(1, 2, 3) nullable(4)
|
||||
int gcc_handle_received_message(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
|
||||
const uint8_t *data, uint16_t length, uint8_t packet_type, uint64_t message_id,
|
||||
bool direct_conn);
|
||||
|
||||
/** @brief Handles a packet fragment.
|
||||
*
|
||||
* If the fragment is incomplete, it gets stored in the recv
|
||||
* array. Otherwise the segment is re-assembled into a complete
|
||||
* payload and processed.
|
||||
*
|
||||
* Return 1 if fragment is successfully handled and is not the end of the sequence.
|
||||
* Return 0 if fragment is the end of a sequence and successfully handled.
|
||||
* Return -1 on failure.
|
||||
*/
|
||||
non_null(1, 2, 4) nullable(5, 9)
|
||||
int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, GC_Connection *gconn,
|
||||
const uint8_t *chunk, uint16_t length, uint8_t packet_type, uint64_t message_id,
|
||||
void *userdata);
|
||||
|
||||
/** @brief Return array index for message_id */
|
||||
uint16_t gcc_get_array_index(uint64_t message_id);
|
||||
|
||||
/** @brief Removes send_array item with message_id.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id);
|
||||
|
||||
/** @brief Sets the send_message_id and send_array_start for `gconn` to `id`.
|
||||
*
|
||||
* This should only be used to initialize a new lossless connection.
|
||||
*/
|
||||
non_null()
|
||||
void gcc_set_send_message_id(GC_Connection *gconn, uint64_t id);
|
||||
|
||||
/** @brief Sets the received_message_id for `gconn` to `id`. */
|
||||
non_null()
|
||||
void gcc_set_recv_message_id(GC_Connection *gconn, uint64_t id);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the ip_port is set for gconn.
|
||||
*/
|
||||
non_null()
|
||||
bool gcc_ip_port_is_set(const GC_Connection *gconn);
|
||||
|
||||
/**
|
||||
* @brief Sets the ip_port for gconn to ipp.
|
||||
*
|
||||
* If ipp is not set this function has no effect.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
void gcc_set_ip_port(GC_Connection *gconn, const IP_Port *ipp);
|
||||
|
||||
/** @brief Copies a random TCP relay node from gconn to tcp_node.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Connection *gconn);
|
||||
|
||||
/** @brief Saves tcp_node to gconn's list of connected tcp relays.
|
||||
*
|
||||
* If relays list is full a random node is overwritten with the new node.
|
||||
*
|
||||
* Return 0 on success.
|
||||
* Return -1 on failure.
|
||||
* Return -2 if node is already in list.
|
||||
*/
|
||||
non_null()
|
||||
int gcc_save_tcp_relay(const Random *rng, GC_Connection *gconn, const Node_format *tcp_node);
|
||||
|
||||
/** @brief Checks for and handles messages that are in proper sequence in gconn's recv_array.
|
||||
* This should always be called after a new packet is successfully handled.
|
||||
*/
|
||||
non_null(1, 2, 3) nullable(5)
|
||||
void gcc_check_recv_array(const GC_Session *c, GC_Chat *chat, GC_Connection *gconn, uint32_t peer_number,
|
||||
void *userdata);
|
||||
|
||||
/** @brief Attempts to re-send lossless packets that have not yet received an ack. */
|
||||
non_null()
|
||||
void gcc_resend_packets(const GC_Chat *chat, GC_Connection *gconn);
|
||||
|
||||
/**
|
||||
* Uses public encryption key `sender_pk` and the shared secret key associated with `gconn`
|
||||
* to generate a shared 32-byte encryption key that can be used by the owners of both keys for symmetric
|
||||
* encryption and decryption.
|
||||
*
|
||||
* Puts the result in the shared session key buffer for `gconn`, which must have room for
|
||||
* CRYPTO_SHARED_KEY_SIZE bytes. This resulting shared key should be treated as a secret key.
|
||||
*/
|
||||
non_null()
|
||||
void gcc_make_session_shared_key(GC_Connection *gconn, const uint8_t *sender_pk);
|
||||
|
||||
/** @brief Return true if we have a direct connection with `gconn`. */
|
||||
non_null()
|
||||
bool gcc_conn_is_direct(const Mono_Time *mono_time, const GC_Connection *gconn);
|
||||
|
||||
/** @brief Return true if a direct UDP connection is possible with `gconn`. */
|
||||
non_null()
|
||||
bool gcc_direct_conn_is_possible(const GC_Chat *chat, const GC_Connection *gconn);
|
||||
|
||||
/** @brief Sends a packet to the peer associated with gconn.
|
||||
*
|
||||
* This is a lower level function that does not encrypt or wrap the packet.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool gcc_send_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *packet, uint16_t length);
|
||||
|
||||
/** @brief Sends a lossless packet to `gconn` comprised of `data` of size `length`.
|
||||
*
|
||||
* This function will add the packet to the lossless send array, encrypt/wrap it using the
|
||||
* shared key associated with `gconn`, and send it over the wire.
|
||||
*
|
||||
* Return 0 on success.
|
||||
* Return -1 if the packet couldn't be added to the send array.
|
||||
* Return -2 if the packet failed to be encrypted or failed to send.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
int gcc_send_lossless_packet(const GC_Chat *chat, GC_Connection *gconn, const uint8_t *data, uint16_t length,
|
||||
uint8_t packet_type);
|
||||
|
||||
/** @brief Splits a lossless packet up into fragments, wraps each fragment in a GP_FRAGMENT
|
||||
* header, encrypts them, and send them in succession.
|
||||
*
|
||||
* This function will first try to add each packet fragment to the send array as an atomic
|
||||
* unit. If any chunk fails to be added the process will be reversed and an error will be
|
||||
* returned. Otherwise it will then try to send all the fragments in succession.
|
||||
*
|
||||
* Return true if all fragments are successfully added to the send array.
|
||||
*/
|
||||
non_null()
|
||||
bool gcc_send_lossless_packet_fragments(const GC_Chat *chat, GC_Connection *gconn, const uint8_t *data,
|
||||
uint16_t length, uint8_t packet_type);
|
||||
|
||||
|
||||
/** @brief Encrypts `data` of `length` bytes, designated by `message_id`, using the shared key
|
||||
* associated with `gconn` and sends lossless packet over the wire.
|
||||
*
|
||||
* This function does not add the packet to the send array.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
bool gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *data,
|
||||
uint16_t length, uint64_t message_id, uint8_t packet_type);
|
||||
|
||||
/** @brief Called when a peer leaves the group. */
|
||||
non_null()
|
||||
void gcc_peer_cleanup(GC_Connection *gconn);
|
||||
|
||||
/** @brief Called on group exit. */
|
||||
non_null()
|
||||
void gcc_cleanup(const GC_Chat *chat);
|
||||
|
||||
#endif // GROUP_CONNECTION_H
|
868
external/toxcore/c-toxcore/toxcore/group_moderation.c
vendored
Normal file
868
external/toxcore/c-toxcore/toxcore/group_moderation.c
vendored
Normal file
@ -0,0 +1,868 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of massive text only group chats.
|
||||
*/
|
||||
|
||||
#include "group_moderation.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ccompat.h"
|
||||
#include "crypto_core.h"
|
||||
#include "mono_time.h"
|
||||
#include "network.h"
|
||||
#include "util.h"
|
||||
|
||||
static_assert(MOD_SANCTIONS_CREDS_SIZE <= MAX_PACKET_SIZE_NO_HEADERS,
|
||||
"MOD_SANCTIONS_CREDS_SIZE must be <= the maximum allowed payload size");
|
||||
static_assert(MOD_MAX_NUM_SANCTIONS * MOD_SANCTION_PACKED_SIZE + MOD_SANCTIONS_CREDS_SIZE <= MAX_PACKET_SIZE_NO_HEADERS,
|
||||
"MOD_MAX_NUM_SANCTIONS must be able to fit inside the maximum allowed payload size");
|
||||
static_assert(MOD_MAX_NUM_MODERATORS * MOD_LIST_ENTRY_SIZE <= MAX_PACKET_SIZE_NO_HEADERS,
|
||||
"MOD_MAX_NUM_MODERATORS must be able to fit insize the maximum allowed payload size");
|
||||
static_assert(MOD_MAX_NUM_MODERATORS <= MOD_MAX_NUM_MODERATORS_LIMIT,
|
||||
"MOD_MAX_NUM_MODERATORS must be <= MOD_MAX_NUM_MODERATORS_LIMIT");
|
||||
static_assert(MOD_MAX_NUM_SANCTIONS <= MOD_MAX_NUM_SANCTIONS_LIMIT,
|
||||
"MOD_MAX_NUM_SANCTIONS must be <= MOD_MAX_NUM_SANCTIONS_LIMIT");
|
||||
|
||||
uint16_t mod_list_packed_size(const Moderation *moderation)
|
||||
{
|
||||
return moderation->num_mods * MOD_LIST_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length, uint16_t num_mods)
|
||||
{
|
||||
if (length < num_mods * MOD_LIST_ENTRY_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mod_list_cleanup(moderation);
|
||||
|
||||
if (num_mods == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t **tmp_list = (uint8_t **)calloc(num_mods, sizeof(uint8_t *));
|
||||
|
||||
if (tmp_list == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t unpacked_len = 0;
|
||||
|
||||
for (uint16_t i = 0; i < num_mods; ++i) {
|
||||
tmp_list[i] = (uint8_t *)malloc(sizeof(uint8_t) * MOD_LIST_ENTRY_SIZE);
|
||||
|
||||
if (tmp_list[i] == nullptr) {
|
||||
free_uint8_t_pointer_array(tmp_list, i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(tmp_list[i], &data[i * MOD_LIST_ENTRY_SIZE], MOD_LIST_ENTRY_SIZE);
|
||||
unpacked_len += MOD_LIST_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
moderation->mod_list = tmp_list;
|
||||
moderation->num_mods = num_mods;
|
||||
|
||||
return unpacked_len;
|
||||
}
|
||||
|
||||
void mod_list_pack(const Moderation *moderation, uint8_t *data)
|
||||
{
|
||||
for (uint16_t i = 0; i < moderation->num_mods; ++i) {
|
||||
memcpy(&data[i * MOD_LIST_ENTRY_SIZE], moderation->mod_list[i], MOD_LIST_ENTRY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void mod_list_get_data_hash(uint8_t *hash, const uint8_t *packed_mod_list, uint16_t length)
|
||||
{
|
||||
crypto_sha256(hash, packed_mod_list, length);
|
||||
}
|
||||
|
||||
bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash)
|
||||
{
|
||||
if (moderation->num_mods == 0) {
|
||||
memset(hash, 0, MOD_MODERATION_HASH_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t data_buf_size = mod_list_packed_size(moderation);
|
||||
|
||||
assert(data_buf_size > 0);
|
||||
|
||||
uint8_t *data = (uint8_t *)malloc(data_buf_size);
|
||||
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mod_list_pack(moderation, data);
|
||||
|
||||
mod_list_get_data_hash(hash, data, data_buf_size);
|
||||
|
||||
free(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns moderator list index for public_sig_key.
|
||||
* Returns -1 if key is not in the list.
|
||||
*/
|
||||
non_null()
|
||||
static int mod_list_index_of_sig_pk(const Moderation *moderation, const uint8_t *public_sig_key)
|
||||
{
|
||||
for (uint16_t i = 0; i < moderation->num_mods; ++i) {
|
||||
if (memcmp(moderation->mod_list[i], public_sig_key, SIG_PUBLIC_KEY_SIZE) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool mod_list_verify_sig_pk(const Moderation *moderation, const uint8_t *sig_pk)
|
||||
{
|
||||
if (memcmp(moderation->founder_public_sig_key, sig_pk, SIG_PUBLIC_KEY_SIZE) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < moderation->num_mods; ++i) {
|
||||
if (memcmp(moderation->mod_list[i], sig_pk, SIG_PUBLIC_KEY_SIZE) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mod_list_remove_index(Moderation *moderation, uint16_t index)
|
||||
{
|
||||
if (index >= moderation->num_mods) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((moderation->num_mods - 1) == 0) {
|
||||
mod_list_cleanup(moderation);
|
||||
return true;
|
||||
}
|
||||
|
||||
--moderation->num_mods;
|
||||
|
||||
if (index != moderation->num_mods) {
|
||||
memcpy(moderation->mod_list[index], moderation->mod_list[moderation->num_mods],
|
||||
MOD_LIST_ENTRY_SIZE);
|
||||
}
|
||||
|
||||
free(moderation->mod_list[moderation->num_mods]);
|
||||
moderation->mod_list[moderation->num_mods] = nullptr;
|
||||
|
||||
uint8_t **tmp_list = (uint8_t **)realloc(moderation->mod_list, moderation->num_mods * sizeof(uint8_t *));
|
||||
|
||||
if (tmp_list == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
moderation->mod_list = tmp_list;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_list_remove_entry(Moderation *moderation, const uint8_t *public_sig_key)
|
||||
{
|
||||
if (moderation->num_mods == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int idx = mod_list_index_of_sig_pk(moderation, public_sig_key);
|
||||
|
||||
if (idx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(idx <= UINT16_MAX);
|
||||
|
||||
return mod_list_remove_index(moderation, (uint16_t)idx);
|
||||
}
|
||||
|
||||
bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data)
|
||||
{
|
||||
if (moderation->num_mods >= MOD_MAX_NUM_MODERATORS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t **tmp_list = (uint8_t **)realloc(moderation->mod_list, (moderation->num_mods + 1) * sizeof(uint8_t *));
|
||||
|
||||
if (tmp_list == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
moderation->mod_list = tmp_list;
|
||||
|
||||
tmp_list[moderation->num_mods] = (uint8_t *)malloc(sizeof(uint8_t) * MOD_LIST_ENTRY_SIZE);
|
||||
|
||||
if (tmp_list[moderation->num_mods] == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(tmp_list[moderation->num_mods], mod_data, MOD_LIST_ENTRY_SIZE);
|
||||
++moderation->num_mods;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_list_cleanup(Moderation *moderation)
|
||||
{
|
||||
free_uint8_t_pointer_array(moderation->mod_list, moderation->num_mods);
|
||||
moderation->num_mods = 0;
|
||||
moderation->mod_list = nullptr;
|
||||
}
|
||||
|
||||
uint16_t sanctions_creds_pack(const Mod_Sanction_Creds *creds, uint8_t *data)
|
||||
{
|
||||
uint16_t packed_len = 0;
|
||||
|
||||
net_pack_u32(data + packed_len, creds->version);
|
||||
packed_len += sizeof(uint32_t);
|
||||
memcpy(data + packed_len, creds->hash, MOD_SANCTION_HASH_SIZE);
|
||||
packed_len += MOD_SANCTION_HASH_SIZE;
|
||||
net_pack_u16(data + packed_len, creds->checksum);
|
||||
packed_len += sizeof(uint16_t);
|
||||
memcpy(data + packed_len, creds->sig_pk, SIG_PUBLIC_KEY_SIZE);
|
||||
packed_len += SIG_PUBLIC_KEY_SIZE;
|
||||
memcpy(data + packed_len, creds->sig, SIGNATURE_SIZE);
|
||||
packed_len += SIGNATURE_SIZE;
|
||||
|
||||
return packed_len;
|
||||
}
|
||||
|
||||
uint16_t sanctions_list_packed_size(uint16_t num_sanctions)
|
||||
{
|
||||
return MOD_SANCTION_PACKED_SIZE * num_sanctions;
|
||||
}
|
||||
|
||||
int sanctions_list_pack(uint8_t *data, uint16_t length, const Mod_Sanction *sanctions, uint16_t num_sanctions,
|
||||
const Mod_Sanction_Creds *creds)
|
||||
{
|
||||
assert(sanctions != nullptr || num_sanctions == 0);
|
||||
assert(sanctions != nullptr || creds != nullptr);
|
||||
|
||||
uint16_t packed_len = 0;
|
||||
|
||||
for (uint16_t i = 0; i < num_sanctions; ++i) {
|
||||
if (packed_len + sizeof(uint8_t) + SIG_PUBLIC_KEY_SIZE + TIME_STAMP_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(data + packed_len, &sanctions[i].type, sizeof(uint8_t));
|
||||
packed_len += sizeof(uint8_t);
|
||||
memcpy(data + packed_len, sanctions[i].setter_public_sig_key, SIG_PUBLIC_KEY_SIZE);
|
||||
packed_len += SIG_PUBLIC_KEY_SIZE;
|
||||
net_pack_u64(data + packed_len, sanctions[i].time_set);
|
||||
packed_len += TIME_STAMP_SIZE;
|
||||
|
||||
const uint8_t sanctions_type = sanctions[i].type;
|
||||
|
||||
if (sanctions_type == SA_OBSERVER) {
|
||||
if (packed_len + ENC_PUBLIC_KEY_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(data + packed_len, sanctions[i].target_public_enc_key, ENC_PUBLIC_KEY_SIZE);
|
||||
packed_len += ENC_PUBLIC_KEY_SIZE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packed_len + SIGNATURE_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Signature must be packed last */
|
||||
memcpy(data + packed_len, sanctions[i].signature, SIGNATURE_SIZE);
|
||||
packed_len += SIGNATURE_SIZE;
|
||||
}
|
||||
|
||||
if (creds == nullptr) {
|
||||
return packed_len;
|
||||
}
|
||||
|
||||
if (length < packed_len || length - packed_len < MOD_SANCTIONS_CREDS_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t cred_len = sanctions_creds_pack(creds, data + packed_len);
|
||||
|
||||
if (cred_len != MOD_SANCTIONS_CREDS_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)(packed_len + cred_len);
|
||||
}
|
||||
|
||||
uint16_t sanctions_creds_unpack(Mod_Sanction_Creds *creds, const uint8_t *data)
|
||||
{
|
||||
uint16_t len_processed = 0;
|
||||
|
||||
net_unpack_u32(data + len_processed, &creds->version);
|
||||
len_processed += sizeof(uint32_t);
|
||||
memcpy(creds->hash, data + len_processed, MOD_SANCTION_HASH_SIZE);
|
||||
len_processed += MOD_SANCTION_HASH_SIZE;
|
||||
net_unpack_u16(data + len_processed, &creds->checksum);
|
||||
len_processed += sizeof(uint16_t);
|
||||
memcpy(creds->sig_pk, data + len_processed, SIG_PUBLIC_KEY_SIZE);
|
||||
len_processed += SIG_PUBLIC_KEY_SIZE;
|
||||
memcpy(creds->sig, data + len_processed, SIGNATURE_SIZE);
|
||||
len_processed += SIGNATURE_SIZE;
|
||||
|
||||
return len_processed;
|
||||
}
|
||||
|
||||
int sanctions_list_unpack(Mod_Sanction *sanctions, Mod_Sanction_Creds *creds, uint16_t max_sanctions,
|
||||
const uint8_t *data, uint16_t length, uint16_t *processed_data_len)
|
||||
{
|
||||
uint16_t num = 0;
|
||||
uint16_t len_processed = 0;
|
||||
|
||||
while (num < max_sanctions && num < MOD_MAX_NUM_SANCTIONS && len_processed < length) {
|
||||
if (len_processed + sizeof(uint8_t) + SIG_PUBLIC_KEY_SIZE + TIME_STAMP_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&sanctions[num].type, data + len_processed, sizeof(uint8_t));
|
||||
len_processed += sizeof(uint8_t);
|
||||
memcpy(sanctions[num].setter_public_sig_key, data + len_processed, SIG_PUBLIC_KEY_SIZE);
|
||||
len_processed += SIG_PUBLIC_KEY_SIZE;
|
||||
net_unpack_u64(data + len_processed, &sanctions[num].time_set);
|
||||
len_processed += TIME_STAMP_SIZE;
|
||||
|
||||
if (sanctions[num].type == SA_OBSERVER) {
|
||||
if (len_processed + ENC_PUBLIC_KEY_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(sanctions[num].target_public_enc_key, data + len_processed, ENC_PUBLIC_KEY_SIZE);
|
||||
len_processed += ENC_PUBLIC_KEY_SIZE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len_processed + SIGNATURE_SIZE > length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(sanctions[num].signature, data + len_processed, SIGNATURE_SIZE);
|
||||
len_processed += SIGNATURE_SIZE;
|
||||
|
||||
++num;
|
||||
}
|
||||
|
||||
if (length <= len_processed || length - len_processed < MOD_SANCTIONS_CREDS_SIZE) {
|
||||
if (length != len_processed) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (processed_data_len != nullptr) {
|
||||
*processed_data_len = len_processed;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
const uint16_t creds_len = sanctions_creds_unpack(creds, data + len_processed);
|
||||
|
||||
if (creds_len != MOD_SANCTIONS_CREDS_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (processed_data_len != nullptr) {
|
||||
*processed_data_len = len_processed + creds_len;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Creates a new sanction list hash and puts it in hash.
|
||||
*
|
||||
* The hash is derived from the signature of all entries plus the version number.
|
||||
* hash must have room for at least MOD_SANCTION_HASH_SIZE bytes.
|
||||
*
|
||||
* If num_sanctions is 0 the hash is zeroed.
|
||||
*
|
||||
* Return true on success.
|
||||
*/
|
||||
non_null(4) nullable(1)
|
||||
static bool sanctions_list_make_hash(const Mod_Sanction *sanctions, uint32_t new_version, uint16_t num_sanctions,
|
||||
uint8_t *hash)
|
||||
{
|
||||
if (num_sanctions == 0 || sanctions == nullptr) {
|
||||
memset(hash, 0, MOD_SANCTION_HASH_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t sig_data_size = num_sanctions * SIGNATURE_SIZE;
|
||||
const size_t data_buf_size = sig_data_size + sizeof(uint32_t);
|
||||
|
||||
// check for integer overflower
|
||||
if (data_buf_size < num_sanctions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data = (uint8_t *)malloc(data_buf_size);
|
||||
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < num_sanctions; ++i) {
|
||||
memcpy(&data[i * SIGNATURE_SIZE], sanctions[i].signature, SIGNATURE_SIZE);
|
||||
}
|
||||
|
||||
memcpy(&data[sig_data_size], &new_version, sizeof(uint32_t));
|
||||
crypto_sha256(hash, data, data_buf_size);
|
||||
|
||||
free(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Verifies that sanction contains valid info and was assigned by a current mod or group founder.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
static bool sanctions_list_validate_entry(const Moderation *moderation, const Mod_Sanction *sanction)
|
||||
{
|
||||
if (!mod_list_verify_sig_pk(moderation, sanction->setter_public_sig_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sanction->type >= SA_INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sanction->time_set == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t packed_data[MOD_SANCTION_PACKED_SIZE];
|
||||
const int packed_len = sanctions_list_pack(packed_data, sizeof(packed_data), sanction, 1, nullptr);
|
||||
|
||||
if (packed_len <= (int) SIGNATURE_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return crypto_signature_verify(sanction->signature, packed_data, packed_len - SIGNATURE_SIZE,
|
||||
sanction->setter_public_sig_key);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint16_t sanctions_creds_get_checksum(const Mod_Sanction_Creds *creds)
|
||||
{
|
||||
return data_checksum(creds->hash, sizeof(creds->hash));
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void sanctions_creds_set_checksum(Mod_Sanction_Creds *creds)
|
||||
{
|
||||
creds->checksum = sanctions_creds_get_checksum(creds);
|
||||
}
|
||||
|
||||
bool sanctions_list_make_creds(Moderation *moderation)
|
||||
{
|
||||
const Mod_Sanction_Creds old_creds = moderation->sanctions_creds;
|
||||
|
||||
++moderation->sanctions_creds.version;
|
||||
|
||||
memcpy(moderation->sanctions_creds.sig_pk, moderation->self_public_sig_key, SIG_PUBLIC_KEY_SIZE);
|
||||
|
||||
uint8_t hash[MOD_SANCTION_HASH_SIZE];
|
||||
|
||||
if (!sanctions_list_make_hash(moderation->sanctions, moderation->sanctions_creds.version,
|
||||
moderation->num_sanctions, hash)) {
|
||||
moderation->sanctions_creds = old_creds;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(moderation->sanctions_creds.hash, hash, MOD_SANCTION_HASH_SIZE);
|
||||
|
||||
sanctions_creds_set_checksum(&moderation->sanctions_creds);
|
||||
|
||||
if (!crypto_signature_create(moderation->sanctions_creds.sig, moderation->sanctions_creds.hash,
|
||||
MOD_SANCTION_HASH_SIZE, moderation->self_secret_sig_key)) {
|
||||
moderation->sanctions_creds = old_creds;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Validates sanction list credentials.
|
||||
*
|
||||
* Verifies that:
|
||||
* - the public signature key belongs to a mod or the founder
|
||||
* - the signature for the hash was made by the owner of the public signature key.
|
||||
* - the received hash matches our own hash of the new sanctions list
|
||||
* - the received checksum matches the received hash
|
||||
* - the new version is >= our current version
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null(1, 3) nullable(2)
|
||||
static bool sanctions_creds_validate(const Moderation *moderation, const Mod_Sanction *sanctions,
|
||||
const Mod_Sanction_Creds *creds, uint16_t num_sanctions)
|
||||
{
|
||||
if (!mod_list_verify_sig_pk(moderation, creds->sig_pk)) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid credentials signature pk");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t hash[MOD_SANCTION_HASH_SIZE];
|
||||
|
||||
if (!sanctions_list_make_hash(sanctions, creds->version, num_sanctions, hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(hash, creds->hash, MOD_SANCTION_HASH_SIZE) != 0) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid credentials hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (creds->checksum != sanctions_creds_get_checksum(creds)) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid credentials checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moderation->shared_state_version > 0) {
|
||||
if ((creds->version < moderation->sanctions_creds.version)
|
||||
&& !(creds->version == 0 && moderation->sanctions_creds.version == UINT32_MAX)) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid version");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!crypto_signature_verify(creds->sig, hash, MOD_SANCTION_HASH_SIZE, creds->sig_pk)) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sanctions_list_check_integrity(const Moderation *moderation, const Mod_Sanction_Creds *creds,
|
||||
const Mod_Sanction *sanctions, uint16_t num_sanctions)
|
||||
{
|
||||
for (uint16_t i = 0; i < num_sanctions; ++i) {
|
||||
if (!sanctions_list_validate_entry(moderation, &sanctions[i])) {
|
||||
LOGGER_WARNING(moderation->log, "Invalid entry");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return sanctions_creds_validate(moderation, sanctions, creds, num_sanctions);
|
||||
}
|
||||
|
||||
/** @brief Validates a sanctions list if credentials are supplied. If successful,
|
||||
* or if no credentials are supplied, assigns new sanctions list and credentials
|
||||
* to moderation object.
|
||||
*
|
||||
* @param moderation The moderation object being operated on.
|
||||
* @param new_sanctions The sanctions list to validate and assign to moderation object.
|
||||
* @param new_creds The new sanctions credentials to be assigned to moderation object.
|
||||
* @param num_sanctions The number of sanctions in the sanctions list.
|
||||
*
|
||||
* @retval false if sanctions credentials validation fails.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
static bool sanctions_apply_new(Moderation *moderation, Mod_Sanction *new_sanctions,
|
||||
const Mod_Sanction_Creds *new_creds,
|
||||
uint16_t num_sanctions)
|
||||
{
|
||||
if (new_creds != nullptr) {
|
||||
if (!sanctions_creds_validate(moderation, new_sanctions, new_creds, num_sanctions)) {
|
||||
LOGGER_WARNING(moderation->log, "Failed to validate credentials");
|
||||
return false;
|
||||
}
|
||||
|
||||
moderation->sanctions_creds = *new_creds;
|
||||
}
|
||||
|
||||
sanctions_list_cleanup(moderation);
|
||||
moderation->sanctions = new_sanctions;
|
||||
moderation->num_sanctions = num_sanctions;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Returns a copy of the sanctions list. The caller is responsible for freeing the
|
||||
* memory returned by this function.
|
||||
*/
|
||||
non_null()
|
||||
static Mod_Sanction *sanctions_list_copy(const Mod_Sanction *sanctions, uint16_t num_sanctions)
|
||||
{
|
||||
Mod_Sanction *copy = (Mod_Sanction *)calloc(num_sanctions, sizeof(Mod_Sanction));
|
||||
|
||||
if (copy == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(copy, sanctions, num_sanctions * sizeof(Mod_Sanction));
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** @brief Removes index-th sanction list entry.
|
||||
*
|
||||
* New credentials will be validated if creds is non-null.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null(1) nullable(3)
|
||||
static bool sanctions_list_remove_index(Moderation *moderation, uint16_t index, const Mod_Sanction_Creds *creds)
|
||||
{
|
||||
if (index >= moderation->num_sanctions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t new_num = moderation->num_sanctions - 1;
|
||||
|
||||
if (new_num == 0) {
|
||||
if (creds != nullptr) {
|
||||
if (!sanctions_creds_validate(moderation, nullptr, creds, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
moderation->sanctions_creds = *creds;
|
||||
}
|
||||
|
||||
sanctions_list_cleanup(moderation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Operate on a copy of the list in case something goes wrong. */
|
||||
Mod_Sanction *sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions);
|
||||
|
||||
if (sanctions_copy == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index != new_num) {
|
||||
sanctions_copy[index] = sanctions_copy[new_num];
|
||||
}
|
||||
|
||||
Mod_Sanction *new_list = (Mod_Sanction *)realloc(sanctions_copy, new_num * sizeof(Mod_Sanction));
|
||||
|
||||
if (new_list == nullptr) {
|
||||
free(sanctions_copy);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sanctions_apply_new(moderation, new_list, creds, new_num)) {
|
||||
free(new_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sanctions_list_remove_observer(Moderation *moderation, const uint8_t *public_key,
|
||||
const Mod_Sanction_Creds *creds)
|
||||
{
|
||||
for (uint16_t i = 0; i < moderation->num_sanctions; ++i) {
|
||||
const Mod_Sanction *curr_sanction = &moderation->sanctions[i];
|
||||
|
||||
if (curr_sanction->type != SA_OBSERVER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(public_key, curr_sanction->target_public_enc_key, ENC_PUBLIC_KEY_SIZE) == 0) {
|
||||
if (!sanctions_list_remove_index(moderation, i, creds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (creds == nullptr) {
|
||||
return sanctions_list_make_creds(moderation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanctions_list_is_observer(const Moderation *moderation, const uint8_t *public_key)
|
||||
{
|
||||
for (uint16_t i = 0; i < moderation->num_sanctions; ++i) {
|
||||
const Mod_Sanction *curr_sanction = &moderation->sanctions[i];
|
||||
|
||||
if (curr_sanction->type != SA_OBSERVER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(curr_sanction->target_public_enc_key, public_key, ENC_PUBLIC_KEY_SIZE) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanctions_list_entry_exists(const Moderation *moderation, const Mod_Sanction *sanction)
|
||||
{
|
||||
if (sanction->type == SA_OBSERVER) {
|
||||
return sanctions_list_is_observer(moderation, sanction->target_public_enc_key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sanction, const Mod_Sanction_Creds *creds)
|
||||
{
|
||||
if (moderation->num_sanctions >= MOD_MAX_NUM_SANCTIONS) {
|
||||
LOGGER_WARNING(moderation->log, "num_sanctions %d exceeds maximum", moderation->num_sanctions);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sanctions_list_validate_entry(moderation, sanction)) {
|
||||
LOGGER_ERROR(moderation->log, "Failed to validate sanction");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sanctions_list_entry_exists(moderation, sanction)) {
|
||||
LOGGER_WARNING(moderation->log, "Attempted to add duplicate sanction");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Operate on a copy of the list in case something goes wrong. */
|
||||
Mod_Sanction *sanctions_copy = nullptr;
|
||||
|
||||
if (moderation->num_sanctions > 0) {
|
||||
sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions);
|
||||
|
||||
if (sanctions_copy == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t index = moderation->num_sanctions;
|
||||
Mod_Sanction *new_list = (Mod_Sanction *)realloc(sanctions_copy, (index + 1) * sizeof(Mod_Sanction));
|
||||
|
||||
if (new_list == nullptr) {
|
||||
free(sanctions_copy);
|
||||
return false;
|
||||
}
|
||||
|
||||
new_list[index] = *sanction;
|
||||
|
||||
if (!sanctions_apply_new(moderation, new_list, creds, index + 1)) {
|
||||
free(new_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Signs packed sanction data.
|
||||
*
|
||||
* This function must be called by the owner of the entry's public_sig_key.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
static bool sanctions_list_sign_entry(const Moderation *moderation, Mod_Sanction *sanction)
|
||||
{
|
||||
uint8_t packed_data[MOD_SANCTION_PACKED_SIZE];
|
||||
const int packed_len = sanctions_list_pack(packed_data, sizeof(packed_data), sanction, 1, nullptr);
|
||||
|
||||
if (packed_len <= (int) SIGNATURE_SIZE) {
|
||||
LOGGER_ERROR(moderation->log, "Failed to pack sanctions list: %d", packed_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
return crypto_signature_create(sanction->signature, packed_data, packed_len - SIGNATURE_SIZE,
|
||||
moderation->self_secret_sig_key);
|
||||
}
|
||||
|
||||
bool sanctions_list_make_entry(Moderation *moderation, const uint8_t *public_key, Mod_Sanction *sanction,
|
||||
uint8_t type)
|
||||
{
|
||||
*sanction = (Mod_Sanction) {
|
||||
0
|
||||
};
|
||||
|
||||
if (type == SA_OBSERVER) {
|
||||
memcpy(sanction->target_public_enc_key, public_key, ENC_PUBLIC_KEY_SIZE);
|
||||
} else {
|
||||
LOGGER_ERROR(moderation->log, "Tried to create sanction with invalid type: %u", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(sanction->setter_public_sig_key, moderation->self_public_sig_key, SIG_PUBLIC_KEY_SIZE);
|
||||
|
||||
sanction->time_set = (uint64_t)time(nullptr);
|
||||
sanction->type = type;
|
||||
|
||||
if (!sanctions_list_sign_entry(moderation, sanction)) {
|
||||
LOGGER_ERROR(moderation->log, "Failed to sign sanction");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sanctions_list_add_entry(moderation, sanction, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sanctions_list_make_creds(moderation)) {
|
||||
LOGGER_ERROR(moderation->log, "Failed to make credentials for new sanction");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
uint16_t sanctions_list_replace_sig(Moderation *moderation, const uint8_t *public_sig_key)
|
||||
{
|
||||
uint16_t count = 0;
|
||||
|
||||
for (uint16_t i = 0; i < moderation->num_sanctions; ++i) {
|
||||
if (memcmp(moderation->sanctions[i].setter_public_sig_key, public_sig_key, SIG_PUBLIC_KEY_SIZE) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(moderation->sanctions[i].setter_public_sig_key, moderation->self_public_sig_key, SIG_PUBLIC_KEY_SIZE);
|
||||
|
||||
if (!sanctions_list_sign_entry(moderation, &moderation->sanctions[i])) {
|
||||
LOGGER_ERROR(moderation->log, "Failed to sign sanction");
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
if (!sanctions_list_make_creds(moderation)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void sanctions_list_cleanup(Moderation *moderation)
|
||||
{
|
||||
if (moderation->sanctions != nullptr) {
|
||||
free(moderation->sanctions);
|
||||
}
|
||||
|
||||
moderation->sanctions = nullptr;
|
||||
moderation->num_sanctions = 0;
|
||||
}
|
296
external/toxcore/c-toxcore/toxcore/group_moderation.h
vendored
Normal file
296
external/toxcore/c-toxcore/toxcore/group_moderation.h
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of massive text only group chats.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_GROUP_MODERATION_H
|
||||
#define C_TOXCORE_TOXCORE_GROUP_MODERATION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "DHT.h"
|
||||
#include "logger.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MOD_MODERATION_HASH_SIZE CRYPTO_SHA256_SIZE
|
||||
#define MOD_LIST_ENTRY_SIZE SIG_PUBLIC_KEY_SIZE
|
||||
#define MOD_SANCTION_HASH_SIZE CRYPTO_SHA256_SIZE
|
||||
|
||||
#define TIME_STAMP_SIZE sizeof(uint64_t)
|
||||
|
||||
/* The packed size of a Mod_Sanction_Creds */
|
||||
#define MOD_SANCTIONS_CREDS_SIZE (sizeof(uint32_t) + MOD_SANCTION_HASH_SIZE + sizeof(uint16_t) +\
|
||||
SIG_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
|
||||
|
||||
/* The packed size of a Mod_Sanction */
|
||||
#define MOD_SANCTION_PACKED_SIZE (SIG_PUBLIC_KEY_SIZE + TIME_STAMP_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + SIGNATURE_SIZE)
|
||||
|
||||
/* The max size of a groupchat packet with 100 bytes reserved for header data */
|
||||
#define MAX_PACKET_SIZE_NO_HEADERS 49900
|
||||
|
||||
/* The maximum possible number of moderators that can be sent in a group packet sequence. */
|
||||
#define MOD_MAX_NUM_MODERATORS_LIMIT (((MAX_PACKET_SIZE_NO_HEADERS) / (MOD_LIST_ENTRY_SIZE)))
|
||||
|
||||
/* The maximum number of moderators that we allow in a group: 100 */
|
||||
#define MOD_MAX_NUM_MODERATORS ((MOD_MAX_NUM_MODERATORS_LIMIT / 16) + 3)
|
||||
|
||||
/* The maximum number of sanctions that be sent in a group packet sequence. */
|
||||
#define MOD_MAX_NUM_SANCTIONS_LIMIT (((MAX_PACKET_SIZE_NO_HEADERS - (MOD_SANCTIONS_CREDS_SIZE)) / (MOD_SANCTION_PACKED_SIZE)))
|
||||
|
||||
/* The maximum number of sanctions that we allow in a group: 30 */
|
||||
#define MOD_MAX_NUM_SANCTIONS (MOD_MAX_NUM_SANCTIONS_LIMIT / 12)
|
||||
|
||||
typedef enum Mod_Sanction_Type {
|
||||
SA_OBSERVER = 0x00,
|
||||
SA_INVALID = 0x01,
|
||||
} Mod_Sanction_Type;
|
||||
|
||||
typedef struct Mod_Sanction_Creds {
|
||||
uint32_t version;
|
||||
uint8_t hash[MOD_SANCTION_HASH_SIZE]; // hash of all sanctions list signatures + version
|
||||
uint16_t checksum; // a sum of the hash
|
||||
uint8_t sig_pk[SIG_PUBLIC_KEY_SIZE]; // Last mod to have modified the sanctions list
|
||||
uint8_t sig[SIGNATURE_SIZE]; // signature of hash, signed by sig_pk
|
||||
} Mod_Sanction_Creds;
|
||||
|
||||
/** Holds data pertaining to a peer who has been sanctioned. */
|
||||
typedef struct Mod_Sanction {
|
||||
uint8_t setter_public_sig_key[SIG_PUBLIC_KEY_SIZE];
|
||||
|
||||
// TODO(Jfreegman): This timestamp can potentially be used to track a user across
|
||||
// different group chats if they're a moderator and set many sanctions across the
|
||||
// different groups. This should be addressed in the future.
|
||||
uint64_t time_set;
|
||||
|
||||
uint8_t type;
|
||||
uint8_t target_public_enc_key[ENC_PUBLIC_KEY_SIZE];
|
||||
|
||||
/* Signature of all above packed data signed by the owner of public_sig_key */
|
||||
uint8_t signature[SIGNATURE_SIZE];
|
||||
} Mod_Sanction;
|
||||
|
||||
typedef struct Moderation {
|
||||
const Logger *log;
|
||||
|
||||
Mod_Sanction *sanctions;
|
||||
uint16_t num_sanctions;
|
||||
|
||||
Mod_Sanction_Creds sanctions_creds;
|
||||
|
||||
uint8_t **mod_list; // array of public signature keys of all the mods
|
||||
uint16_t num_mods;
|
||||
|
||||
// copies from parent/sibling chat/shared state objects
|
||||
uint8_t founder_public_sig_key[SIG_PUBLIC_KEY_SIZE];
|
||||
uint8_t self_public_sig_key[SIG_PUBLIC_KEY_SIZE];
|
||||
uint8_t self_secret_sig_key[SIG_SECRET_KEY_SIZE];
|
||||
uint32_t shared_state_version;
|
||||
} Moderation;
|
||||
|
||||
/** @brief Returns the size in bytes of the packed moderation list. */
|
||||
non_null()
|
||||
uint16_t mod_list_packed_size(const Moderation *moderation);
|
||||
|
||||
/** @brief Unpacks data into the moderator list.
|
||||
*
|
||||
* @param data should contain num_mods entries of size MOD_LIST_ENTRY_SIZE.
|
||||
*
|
||||
* Returns length of unpacked data on success.
|
||||
* Returns -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length, uint16_t num_mods);
|
||||
|
||||
/** @brief Packs moderator list into data.
|
||||
* @param data must have room for the number of bytes returned by `mod_list_packed_size`.
|
||||
*/
|
||||
non_null()
|
||||
void mod_list_pack(const Moderation *moderation, uint8_t *data);
|
||||
|
||||
/** @brief Creates a new moderator list hash and puts it in `hash`.
|
||||
*
|
||||
* @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
|
||||
*
|
||||
* If num_mods is 0 the hash is zeroed.
|
||||
*
|
||||
* Returns true on sucess.
|
||||
*/
|
||||
non_null()
|
||||
bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash);
|
||||
|
||||
/** @brief Puts a sha256 hash of `packed_mod_list` of `length` bytes in `hash`.
|
||||
*
|
||||
* @param hash must have room for at least MOD_MODERATION_HASH_SIZE bytes.
|
||||
*/
|
||||
non_null()
|
||||
void mod_list_get_data_hash(uint8_t *hash, const uint8_t *packed_mod_list, uint16_t length);
|
||||
|
||||
/** @brief Removes moderator at index-th position in the moderator list.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool mod_list_remove_index(Moderation *moderation, uint16_t index);
|
||||
|
||||
/** @brief Removes public_sig_key from the moderator list.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool mod_list_remove_entry(Moderation *moderation, const uint8_t *public_sig_key);
|
||||
|
||||
/** @brief Adds a mod to the moderator list.
|
||||
*
|
||||
* @param mod_data must be MOD_LIST_ENTRY_SIZE bytes.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data);
|
||||
|
||||
/** @return true if the public signature key belongs to a moderator or the founder */
|
||||
non_null()
|
||||
bool mod_list_verify_sig_pk(const Moderation *moderation, const uint8_t *sig_pk);
|
||||
|
||||
/** @brief Frees all memory associated with the moderator list and sets num_mods to 0. */
|
||||
nullable(1)
|
||||
void mod_list_cleanup(Moderation *moderation);
|
||||
|
||||
/** @brief Returns the size in bytes of num_sanctions packed sanctions. */
|
||||
uint16_t sanctions_list_packed_size(uint16_t num_sanctions);
|
||||
|
||||
/** @brief Packs sanctions into data. Additionally packs the sanctions credentials into creds.
|
||||
*
|
||||
* @param data The byte array being packed. Must have room for the number of bytes returned
|
||||
* by `sanctions_list_packed_size`.
|
||||
* @param length The size of the byte array.
|
||||
* @param sanctions The sanctions list.
|
||||
* @param num_sanctions The number of sanctions in the sanctions list. This value must be the same
|
||||
* value used when calling `sanctions_list_packed_size`.
|
||||
* @param creds The credentials object to fill.
|
||||
*
|
||||
* @retval The length of packed data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1) nullable(3, 5)
|
||||
int sanctions_list_pack(uint8_t *data, uint16_t length, const Mod_Sanction *sanctions, uint16_t num_sanctions,
|
||||
const Mod_Sanction_Creds *creds);
|
||||
|
||||
/** @brief Unpacks sanctions and new sanctions credentials.
|
||||
*
|
||||
* @param sanctions The sanctions array the sanctions data is unpacked into.
|
||||
* @param creds The creds object the creds data is unpacked into.
|
||||
* @param max_sanctions The maximum number of sanctions that the sanctions array can hold.
|
||||
* @param data The packed data array.
|
||||
* @param length The size of the packed data.
|
||||
* @param processed_data_len If non-null, will contain the number of processed bytes on success.
|
||||
*
|
||||
* @retval The number of unpacked entries on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1, 2, 4) nullable(6)
|
||||
int sanctions_list_unpack(Mod_Sanction *sanctions, Mod_Sanction_Creds *creds, uint16_t max_sanctions,
|
||||
const uint8_t *data, uint16_t length, uint16_t *processed_data_len);
|
||||
|
||||
/** @brief Packs sanction list credentials into data.
|
||||
*
|
||||
* @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
|
||||
*
|
||||
* Returns length of packed data.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t sanctions_creds_pack(const Mod_Sanction_Creds *creds, uint8_t *data);
|
||||
|
||||
/** @brief Unpacks sanctions credentials into creds from data.
|
||||
*
|
||||
* @param data must have room for MOD_SANCTIONS_CREDS_SIZE bytes.
|
||||
*
|
||||
* Returns the length of the data processed.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t sanctions_creds_unpack(Mod_Sanction_Creds *creds, const uint8_t *data);
|
||||
|
||||
/** @brief Updates sanction list credentials.
|
||||
*
|
||||
* Increment version, replace sig_pk with your own, update hash to reflect new
|
||||
* sanction list, and sign new hash signature.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool sanctions_list_make_creds(Moderation *moderation);
|
||||
|
||||
/** @brief Validates all sanctions list entries as well as the list itself.
|
||||
*
|
||||
* Returns true if all entries are valid.
|
||||
* Returns false if one or more entries are invalid.
|
||||
*/
|
||||
non_null()
|
||||
bool sanctions_list_check_integrity(const Moderation *moderation, const Mod_Sanction_Creds *creds,
|
||||
const Mod_Sanction *sanctions, uint16_t num_sanctions);
|
||||
|
||||
/** @brief Adds an entry to the sanctions list.
|
||||
*
|
||||
* The entry is first validated and the resulting new sanction list is
|
||||
* compared against the new credentials.
|
||||
*
|
||||
* Entries must be unique.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sanction, const Mod_Sanction_Creds *creds);
|
||||
|
||||
/** @brief Creates a new sanction entry for `public_key` where type is one of Mod_Sanction_Type.
|
||||
*
|
||||
* New entry is signed and placed in the sanctions list.
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool sanctions_list_make_entry(Moderation *moderation, const uint8_t *public_key, Mod_Sanction *sanction,
|
||||
uint8_t type);
|
||||
|
||||
/** @return true if public key is in the observer list. */
|
||||
non_null()
|
||||
bool sanctions_list_is_observer(const Moderation *moderation, const uint8_t *public_key);
|
||||
|
||||
/** @return true if sanction already exists in the sanctions list. */
|
||||
non_null()
|
||||
bool sanctions_list_entry_exists(const Moderation *moderation, const Mod_Sanction *sanction);
|
||||
|
||||
/** @brief Removes observer entry for public key from sanction list.
|
||||
*
|
||||
* If creds is NULL we make new credentials (this should only be done by a moderator or founder)
|
||||
*
|
||||
* Returns false on failure or if entry was not found.
|
||||
*/
|
||||
non_null(1, 2) nullable(3)
|
||||
bool sanctions_list_remove_observer(Moderation *moderation, const uint8_t *public_key,
|
||||
const Mod_Sanction_Creds *creds);
|
||||
|
||||
/** @brief Replaces all sanctions list signatures made by public_sig_key with the caller's.
|
||||
*
|
||||
* This is called whenever the founder demotes a moderator.
|
||||
*
|
||||
* Returns the number of entries re-signed.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t sanctions_list_replace_sig(Moderation *moderation, const uint8_t *public_sig_key);
|
||||
|
||||
non_null()
|
||||
void sanctions_list_cleanup(Moderation *moderation);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_GROUP_MODERATION_H
|
38
external/toxcore/c-toxcore/toxcore/group_moderation_fuzz_test.cc
vendored
Normal file
38
external/toxcore/c-toxcore/toxcore/group_moderation_fuzz_test.cc
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#include "group_moderation.h"
|
||||
|
||||
#include "../testing/fuzzing/fuzz_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TestModListUnpack(Fuzz_Data &input)
|
||||
{
|
||||
CONSUME1_OR_RETURN(const uint16_t num_mods, input);
|
||||
Moderation mods{};
|
||||
mod_list_unpack(&mods, input.data, input.size, num_mods);
|
||||
mod_list_cleanup(&mods);
|
||||
}
|
||||
|
||||
void TestSanctionsListUnpack(Fuzz_Data &input)
|
||||
{
|
||||
Mod_Sanction sanctions[10];
|
||||
Mod_Sanction_Creds creds;
|
||||
uint16_t processed_data_len;
|
||||
sanctions_list_unpack(sanctions, &creds, 10, input.data, input.size, &processed_data_len);
|
||||
}
|
||||
|
||||
void TestSanctionCredsUnpack(Fuzz_Data &input)
|
||||
{
|
||||
CONSUME_OR_RETURN(const uint8_t *data, input, MOD_SANCTIONS_CREDS_SIZE);
|
||||
Mod_Sanction_Creds creds;
|
||||
sanctions_creds_unpack(&creds, data);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
fuzz_select_target(
|
||||
data, size, TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack);
|
||||
return 0;
|
||||
}
|
251
external/toxcore/c-toxcore/toxcore/group_moderation_test.cc
vendored
Normal file
251
external/toxcore/c-toxcore/toxcore/group_moderation_test.cc
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
#include "group_moderation.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "logger.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ExtPublicKey = std::array<uint8_t, EXT_PUBLIC_KEY_SIZE>;
|
||||
using ExtSecretKey = std::array<uint8_t, EXT_SECRET_KEY_SIZE>;
|
||||
using ModerationHash = std::array<uint8_t, MOD_MODERATION_HASH_SIZE>;
|
||||
|
||||
TEST(ModList, PackedSizeOfEmptyModListIsZero)
|
||||
{
|
||||
Moderation mods{};
|
||||
EXPECT_EQ(mod_list_packed_size(&mods), 0);
|
||||
|
||||
uint8_t byte = 1;
|
||||
mod_list_pack(&mods, &byte);
|
||||
EXPECT_EQ(byte, 1);
|
||||
}
|
||||
|
||||
TEST(ModList, UnpackingZeroSizeArrayIsNoop)
|
||||
{
|
||||
Moderation mods{};
|
||||
const uint8_t byte = 1;
|
||||
EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0);
|
||||
}
|
||||
|
||||
TEST(ModList, AddRemoveMultipleMods)
|
||||
{
|
||||
Moderation mods{};
|
||||
uint8_t sig_pk1[32] = {1};
|
||||
uint8_t sig_pk2[32] = {2};
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1));
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk2));
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods, sig_pk1));
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods, sig_pk2));
|
||||
}
|
||||
|
||||
TEST(ModList, PackingAndUnpackingList)
|
||||
{
|
||||
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
|
||||
Moderation mods{};
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
|
||||
|
||||
std::vector<uint8_t> packed(mod_list_packed_size(&mods));
|
||||
mod_list_pack(&mods, packed.data());
|
||||
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
|
||||
|
||||
Moderation mods2{};
|
||||
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size());
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data()));
|
||||
}
|
||||
|
||||
TEST(ModList, UnpackingTooManyModsFails)
|
||||
{
|
||||
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
|
||||
Moderation mods{};
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
|
||||
|
||||
std::vector<uint8_t> packed(mod_list_packed_size(&mods));
|
||||
mod_list_pack(&mods, packed.data());
|
||||
|
||||
Moderation mods2{};
|
||||
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1);
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
|
||||
}
|
||||
|
||||
TEST(ModList, UnpackingFromEmptyBufferFails)
|
||||
{
|
||||
std::vector<uint8_t> packed(1);
|
||||
|
||||
Moderation mods{};
|
||||
EXPECT_EQ(mod_list_unpack(&mods, packed.end().base(), 0, 1), -1);
|
||||
}
|
||||
|
||||
TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
|
||||
{
|
||||
const Random *rng = system_random();
|
||||
ASSERT_NE(rng, nullptr);
|
||||
|
||||
Moderation mods{};
|
||||
|
||||
// Fill with random data, check that it's zeroed.
|
||||
ModerationHash hash;
|
||||
random_bytes(rng, hash.data(), hash.size());
|
||||
EXPECT_TRUE(mod_list_make_hash(&mods, hash.data()));
|
||||
EXPECT_EQ(hash, ModerationHash{});
|
||||
}
|
||||
|
||||
TEST(ModList, RemoveIndexFromEmptyModListFails)
|
||||
{
|
||||
Moderation mods{};
|
||||
EXPECT_FALSE(mod_list_remove_index(&mods, 0));
|
||||
EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX));
|
||||
}
|
||||
|
||||
TEST(ModList, RemoveEntryFromEmptyModListFails)
|
||||
{
|
||||
Moderation mods{};
|
||||
uint8_t sig_pk[32] = {0};
|
||||
EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk));
|
||||
}
|
||||
|
||||
TEST(ModList, ModListRemoveIndex)
|
||||
{
|
||||
Moderation mods{};
|
||||
uint8_t sig_pk[32] = {1};
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
|
||||
EXPECT_TRUE(mod_list_remove_index(&mods, 0));
|
||||
}
|
||||
|
||||
TEST(ModList, CleanupOnEmptyModsIsNoop)
|
||||
{
|
||||
Moderation mods{};
|
||||
mod_list_cleanup(&mods);
|
||||
}
|
||||
|
||||
TEST(ModList, EmptyModListCannotVerifyAnySigPk)
|
||||
{
|
||||
Moderation mods{};
|
||||
uint8_t sig_pk[32] = {1};
|
||||
EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
|
||||
}
|
||||
|
||||
TEST(ModList, ModListAddVerifyRemoveSigPK)
|
||||
{
|
||||
Moderation mods{};
|
||||
uint8_t sig_pk[32] = {1};
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
|
||||
EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk));
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods, sig_pk));
|
||||
EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
|
||||
}
|
||||
|
||||
TEST(ModList, ModListHashCheck)
|
||||
{
|
||||
Moderation mods1{};
|
||||
uint8_t sig_pk1[32] = {1};
|
||||
std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1;
|
||||
|
||||
EXPECT_TRUE(mod_list_add_entry(&mods1, sig_pk1));
|
||||
EXPECT_TRUE(mod_list_make_hash(&mods1, hash1.data()));
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mods1, sig_pk1));
|
||||
}
|
||||
|
||||
TEST(SanctionsList, PackingIntoUndersizedBufferFails)
|
||||
{
|
||||
Mod_Sanction sanctions[1] = {};
|
||||
std::array<uint8_t, 1> packed;
|
||||
EXPECT_EQ(sanctions_list_pack(packed.data(), packed.size(), sanctions, 1, nullptr), -1);
|
||||
|
||||
uint16_t length = sanctions_list_packed_size(1) - 1;
|
||||
std::vector<uint8_t> packed2(length);
|
||||
EXPECT_EQ(sanctions_list_pack(packed2.data(), packed2.size(), sanctions, 1, nullptr), -1);
|
||||
}
|
||||
|
||||
TEST(SanctionsList, PackUnpackSanctionsCreds)
|
||||
{
|
||||
Moderation mod{};
|
||||
std::array<uint8_t, MOD_SANCTIONS_CREDS_SIZE> packed;
|
||||
EXPECT_EQ(sanctions_creds_pack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
|
||||
EXPECT_EQ(
|
||||
sanctions_creds_unpack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
|
||||
}
|
||||
|
||||
struct SanctionsListMod : ::testing::Test {
|
||||
protected:
|
||||
ExtPublicKey pk;
|
||||
ExtSecretKey sk;
|
||||
Logger *log = logger_new();
|
||||
Moderation mod{};
|
||||
|
||||
Mod_Sanction sanctions[2] = {};
|
||||
const uint8_t sanctioned_pk1[32] = {1};
|
||||
const uint8_t sanctioned_pk2[32] = {2};
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
ASSERT_TRUE(create_extended_keypair(pk.data(), sk.data()));
|
||||
|
||||
mod.log = log;
|
||||
|
||||
memcpy(mod.self_public_sig_key, get_sig_pk(pk.data()), SIG_PUBLIC_KEY_SIZE);
|
||||
memcpy(mod.self_secret_sig_key, get_sig_sk(sk.data()), SIG_SECRET_KEY_SIZE);
|
||||
|
||||
ASSERT_TRUE(mod_list_add_entry(&mod, get_sig_pk(pk.data())));
|
||||
|
||||
EXPECT_FALSE(sanctions_list_check_integrity(&mod, &mod.sanctions_creds, &sanctions[0], 0));
|
||||
EXPECT_FALSE(sanctions_list_check_integrity(&mod, &mod.sanctions_creds, &sanctions[0], 1));
|
||||
EXPECT_FALSE(
|
||||
sanctions_list_check_integrity(&mod, &mod.sanctions_creds, &sanctions[0], UINT16_MAX));
|
||||
|
||||
EXPECT_TRUE(sanctions_list_make_entry(&mod, sanctioned_pk1, &sanctions[0], SA_OBSERVER));
|
||||
EXPECT_TRUE(sanctions_list_check_integrity(
|
||||
&mod, &mod.sanctions_creds, sanctions, mod.num_sanctions));
|
||||
EXPECT_TRUE(sanctions_list_make_entry(&mod, sanctioned_pk2, &sanctions[1], SA_OBSERVER));
|
||||
EXPECT_TRUE(sanctions_list_check_integrity(
|
||||
&mod, &mod.sanctions_creds, sanctions, mod.num_sanctions));
|
||||
}
|
||||
|
||||
~SanctionsListMod() override
|
||||
{
|
||||
EXPECT_TRUE(sanctions_list_remove_observer(&mod, sanctioned_pk1, nullptr));
|
||||
EXPECT_TRUE(sanctions_list_remove_observer(&mod, sanctioned_pk2, nullptr));
|
||||
EXPECT_FALSE(sanctions_list_entry_exists(&mod, &sanctions[0]));
|
||||
EXPECT_FALSE(sanctions_list_entry_exists(&mod, &sanctions[1]));
|
||||
EXPECT_TRUE(mod_list_remove_entry(&mod, get_sig_pk(pk.data())));
|
||||
|
||||
logger_kill(log);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(JFreegman): Split this up into smaller subtests
|
||||
TEST_F(SanctionsListMod, PackUnpackSanction)
|
||||
{
|
||||
std::vector<uint8_t> packed(sanctions_list_packed_size(2));
|
||||
|
||||
EXPECT_EQ(
|
||||
sanctions_list_pack(packed.data(), packed.size(), sanctions, 2, nullptr), packed.size());
|
||||
|
||||
Mod_Sanction unpacked_sanctions[2] = {};
|
||||
uint16_t processed_data_len = 0;
|
||||
|
||||
EXPECT_EQ(sanctions_list_unpack(unpacked_sanctions, &mod.sanctions_creds, 2, packed.data(),
|
||||
packed.size(), &processed_data_len),
|
||||
2);
|
||||
|
||||
EXPECT_EQ(processed_data_len, packed.size());
|
||||
EXPECT_TRUE(sanctions_list_check_integrity(
|
||||
&mod, &mod.sanctions_creds, unpacked_sanctions, mod.num_sanctions));
|
||||
EXPECT_TRUE(sanctions_list_entry_exists(&mod, &unpacked_sanctions[0]));
|
||||
EXPECT_TRUE(sanctions_list_entry_exists(&mod, &unpacked_sanctions[1]));
|
||||
}
|
||||
|
||||
TEST_F(SanctionsListMod, ReplaceSanctionSignatures)
|
||||
{
|
||||
EXPECT_EQ(sanctions_list_replace_sig(&mod, mod.self_public_sig_key), mod.num_sanctions);
|
||||
EXPECT_TRUE(
|
||||
sanctions_list_check_integrity(&mod, &mod.sanctions_creds, sanctions, mod.num_sanctions));
|
||||
}
|
||||
|
||||
} // namespace
|
115
external/toxcore/c-toxcore/toxcore/group_onion_announce.c
vendored
Normal file
115
external/toxcore/c-toxcore/toxcore/group_onion_announce.c
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
#include "group_onion_announce.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccompat.h"
|
||||
|
||||
static_assert(GCA_ANNOUNCE_MAX_SIZE <= ONION_MAX_EXTRA_DATA_SIZE,
|
||||
"GC_Announce does not fit into the onion packet extra data");
|
||||
|
||||
static pack_extra_data_cb pack_group_announces;
|
||||
non_null()
|
||||
static int pack_group_announces(void *object, const Logger *logger, const Mono_Time *mono_time,
|
||||
uint8_t num_nodes, uint8_t *plain, uint16_t plain_size,
|
||||
uint8_t *response, uint16_t response_size, uint16_t offset)
|
||||
{
|
||||
GC_Announces_List *gc_announces_list = (GC_Announces_List *)object;
|
||||
GC_Public_Announce public_announce;
|
||||
|
||||
if (gca_unpack_public_announce(logger, plain, plain_size,
|
||||
&public_announce) == -1) {
|
||||
LOGGER_WARNING(logger, "Failed to unpack public group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const GC_Peer_Announce *new_announce = gca_add_announce(mono_time, gc_announces_list, &public_announce);
|
||||
|
||||
if (new_announce == nullptr) {
|
||||
LOGGER_ERROR(logger, "Failed to add group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
GC_Announce gc_announces[GCA_MAX_SENT_ANNOUNCES];
|
||||
const int num_ann = gca_get_announces(gc_announces_list,
|
||||
gc_announces,
|
||||
GCA_MAX_SENT_ANNOUNCES,
|
||||
public_announce.chat_public_key,
|
||||
new_announce->base_announce.peer_public_key);
|
||||
|
||||
if (num_ann < 0) {
|
||||
LOGGER_ERROR(logger, "failed to get group announce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(num_ann <= UINT8_MAX);
|
||||
|
||||
size_t announces_length = 0;
|
||||
|
||||
if (gca_pack_announces_list(logger, response + offset, response_size - offset, gc_announces, (uint8_t)num_ann,
|
||||
&announces_length) != num_ann) {
|
||||
LOGGER_WARNING(logger, "Failed to pack group announces list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return announces_length;
|
||||
}
|
||||
|
||||
void gca_onion_init(GC_Announces_List *group_announce, Onion_Announce *onion_a)
|
||||
{
|
||||
onion_announce_extra_data_callback(onion_a, GCA_MAX_SENT_ANNOUNCES * sizeof(GC_Announce), pack_group_announces,
|
||||
group_announce);
|
||||
}
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
|
||||
int create_gca_announce_request(
|
||||
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)
|
||||
{
|
||||
if (max_packet_length < ONION_ANNOUNCE_REQUEST_MAX_SIZE || gc_data_length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE +
|
||||
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + GCA_ANNOUNCE_MAX_SIZE];
|
||||
uint8_t *position_in_plain = plain;
|
||||
const size_t encrypted_size = sizeof(plain) - GCA_ANNOUNCE_MAX_SIZE + gc_data_length;
|
||||
|
||||
memcpy(plain, ping_id, ONION_PING_ID_SIZE);
|
||||
position_in_plain += ONION_PING_ID_SIZE;
|
||||
|
||||
memcpy(position_in_plain, client_id, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
position_in_plain += CRYPTO_PUBLIC_KEY_SIZE;
|
||||
|
||||
memcpy(position_in_plain, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
position_in_plain += CRYPTO_PUBLIC_KEY_SIZE;
|
||||
|
||||
memcpy(position_in_plain, &sendback_data, sizeof(sendback_data));
|
||||
position_in_plain += sizeof(sendback_data);
|
||||
|
||||
memcpy(position_in_plain, gc_data, gc_data_length);
|
||||
|
||||
packet[0] = NET_PACKET_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,
|
||||
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;
|
||||
|
||||
if (full_length != ONION_ANNOUNCE_REQUEST_MIN_SIZE + gc_data_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return full_length;
|
||||
}
|
||||
#endif // VANILLA_NACL
|
22
external/toxcore/c-toxcore/toxcore/group_onion_announce.h
vendored
Normal file
22
external/toxcore/c-toxcore/toxcore/group_onion_announce.h
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_GROUP_ONION_ANNOUNCE_H
|
||||
#define C_TOXCORE_TOXCORE_GROUP_ONION_ANNOUNCE_H
|
||||
|
||||
#include "group_announce.h"
|
||||
#include "onion_announce.h"
|
||||
|
||||
non_null()
|
||||
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 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);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_GROUP_ONION_ANNOUNCE_H
|
423
external/toxcore/c-toxcore/toxcore/group_pack.c
vendored
Normal file
423
external/toxcore/c-toxcore/toxcore/group_pack.c
vendored
Normal file
@ -0,0 +1,423 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Packer and unpacker functions for saving and loading groups.
|
||||
*/
|
||||
|
||||
#include "group_pack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bin_pack.h"
|
||||
#include "bin_unpack.h"
|
||||
#include "ccompat.h"
|
||||
#include "util.h"
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_state_values(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 8)) {
|
||||
LOGGER_ERROR(chat->log, "Group state values array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool manually_disconnected = false;
|
||||
uint8_t privacy_state = 0;
|
||||
uint8_t voice_state = 0;
|
||||
|
||||
if (!(bin_unpack_bool(bu, &manually_disconnected)
|
||||
&& bin_unpack_u16(bu, &chat->shared_state.group_name_len)
|
||||
&& bin_unpack_u08(bu, &privacy_state)
|
||||
&& bin_unpack_u16(bu, &chat->shared_state.maxpeers)
|
||||
&& bin_unpack_u16(bu, &chat->shared_state.password_length)
|
||||
&& bin_unpack_u32(bu, &chat->shared_state.version)
|
||||
&& bin_unpack_u32(bu, &chat->shared_state.topic_lock)
|
||||
&& bin_unpack_u08(bu, &voice_state))) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack state value");
|
||||
return false;
|
||||
}
|
||||
|
||||
chat->connection_state = manually_disconnected ? CS_DISCONNECTED : CS_CONNECTING;
|
||||
chat->shared_state.privacy_state = (Group_Privacy_State)privacy_state;
|
||||
chat->shared_state.voice_state = (Group_Voice_State)voice_state;
|
||||
|
||||
// we always load saved groups as private in case the group became private while we were offline.
|
||||
// this will have no detrimental effect if the group is public, as the correct privacy
|
||||
// state will be set via sync.
|
||||
chat->join_type = HJ_PRIVATE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_state_bin(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 5)) {
|
||||
LOGGER_ERROR(chat->log, "Group state binary array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(bin_unpack_bin_fixed(bu, chat->shared_state_sig, SIGNATURE_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->shared_state.founder_public_key, EXT_PUBLIC_KEY_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->shared_state.group_name, chat->shared_state.group_name_len)
|
||||
&& bin_unpack_bin_fixed(bu, chat->shared_state.password, chat->shared_state.password_length)
|
||||
&& bin_unpack_bin_fixed(bu, chat->shared_state.mod_list_hash, MOD_MODERATION_HASH_SIZE))) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack state binary data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_topic_info(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 6)) {
|
||||
LOGGER_ERROR(chat->log, "Group topic array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(bin_unpack_u32(bu, &chat->topic_info.version)
|
||||
&& bin_unpack_u16(bu, &chat->topic_info.length)
|
||||
&& bin_unpack_u16(bu, &chat->topic_info.checksum)
|
||||
&& bin_unpack_bin_fixed(bu, chat->topic_info.topic, chat->topic_info.length)
|
||||
&& bin_unpack_bin_fixed(bu, chat->topic_info.public_sig_key, SIG_PUBLIC_KEY_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->topic_sig, SIGNATURE_SIZE))) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack topic info");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_mod_list(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
LOGGER_ERROR(chat->log, "Group mod list array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bin_unpack_u16(bu, &chat->moderation.num_mods)) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack mod list value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chat->moderation.num_mods == 0) {
|
||||
bin_unpack_nil(bu);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (chat->moderation.num_mods > MOD_MAX_NUM_MODERATORS) {
|
||||
LOGGER_ERROR(chat->log, "moderation count %u exceeds maximum %u", chat->moderation.num_mods, MOD_MAX_NUM_MODERATORS);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *packed_mod_list = (uint8_t *)malloc(chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE);
|
||||
|
||||
if (packed_mod_list == nullptr) {
|
||||
LOGGER_ERROR(chat->log, "Failed to allocate memory for packed mod list");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t packed_size = chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE;
|
||||
|
||||
if (!bin_unpack_bin_fixed(bu, packed_mod_list, packed_size)) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack mod list binary data");
|
||||
free(packed_mod_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mod_list_unpack(&chat->moderation, packed_mod_list, packed_size, chat->moderation.num_mods) == -1) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack mod list info");
|
||||
free(packed_mod_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(packed_mod_list);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_keys(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
LOGGER_ERROR(chat->log, "Group keys array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(bin_unpack_bin_fixed(bu, chat->chat_public_key, EXT_PUBLIC_KEY_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->chat_secret_key, EXT_SECRET_KEY_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->self_public_key, EXT_PUBLIC_KEY_SIZE)
|
||||
&& bin_unpack_bin_fixed(bu, chat->self_secret_key, EXT_SECRET_KEY_SIZE))) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack keys");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_self_info(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
LOGGER_ERROR(chat->log, "Group self info array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t self_nick[MAX_GC_NICK_SIZE];
|
||||
uint16_t self_nick_len = 0;
|
||||
uint8_t self_role = GR_USER;
|
||||
uint8_t self_status = GS_NONE;
|
||||
|
||||
if (!(bin_unpack_u16(bu, &self_nick_len)
|
||||
&& bin_unpack_u08(bu, &self_role)
|
||||
&& bin_unpack_u08(bu, &self_status))) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack self values");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(self_nick_len <= MAX_GC_NICK_SIZE);
|
||||
|
||||
if (!bin_unpack_bin_fixed(bu, self_nick, self_nick_len)) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack self nick bytes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// we have to add ourself before setting self info
|
||||
if (peer_add(chat, nullptr, chat->self_public_key) != 0) {
|
||||
LOGGER_ERROR(chat->log, "Failed to add self to peer list");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(chat->numpeers > 0);
|
||||
|
||||
GC_Peer *self = &chat->group[0];
|
||||
|
||||
memcpy(self->gconn.addr.public_key, chat->self_public_key, EXT_PUBLIC_KEY_SIZE);
|
||||
memcpy(self->nick, self_nick, self_nick_len);
|
||||
self->nick_length = self_nick_len;
|
||||
self->role = (Group_Role)self_role;
|
||||
self->status = (Group_Peer_Status)self_status;
|
||||
self->gconn.confirmed = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool load_unpack_saved_peers(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
LOGGER_ERROR(chat->log, "Group saved peers array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Saved peers
|
||||
uint16_t saved_peers_size = 0;
|
||||
|
||||
if (!bin_unpack_u16(bu, &saved_peers_size)) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack saved peers value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (saved_peers_size == 0) {
|
||||
bin_unpack_nil(bu);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *saved_peers = (uint8_t *)malloc(saved_peers_size * GC_SAVED_PEER_SIZE);
|
||||
|
||||
if (saved_peers == nullptr) {
|
||||
LOGGER_ERROR(chat->log, "Failed to allocate memory for saved peer list");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bin_unpack_bin_fixed(bu, saved_peers, saved_peers_size)) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack saved peers binary data");
|
||||
free(saved_peers);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unpack_gc_saved_peers(chat, saved_peers, saved_peers_size) == -1) {
|
||||
LOGGER_ERROR(chat->log, "Failed to unpack saved peers"); // recoverable error
|
||||
}
|
||||
|
||||
free(saved_peers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gc_load_unpack_group(GC_Chat *chat, Bin_Unpack *bu)
|
||||
{
|
||||
if (!bin_unpack_array_fixed(bu, 7)) {
|
||||
LOGGER_ERROR(chat->log, "Group info array malformed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return load_unpack_state_values(chat, bu)
|
||||
&& load_unpack_state_bin(chat, bu)
|
||||
&& load_unpack_topic_info(chat, bu)
|
||||
&& load_unpack_mod_list(chat, bu)
|
||||
&& load_unpack_keys(chat, bu)
|
||||
&& load_unpack_self_info(chat, bu)
|
||||
&& load_unpack_saved_peers(chat, bu);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_state_values(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 8);
|
||||
bin_pack_bool(bp, chat->connection_state == CS_DISCONNECTED); // 1
|
||||
bin_pack_u16(bp, chat->shared_state.group_name_len); // 2
|
||||
bin_pack_u08(bp, chat->shared_state.privacy_state); // 3
|
||||
bin_pack_u16(bp, chat->shared_state.maxpeers); // 4
|
||||
bin_pack_u16(bp, chat->shared_state.password_length); // 5
|
||||
bin_pack_u32(bp, chat->shared_state.version); // 6
|
||||
bin_pack_u32(bp, chat->shared_state.topic_lock); // 7
|
||||
bin_pack_u08(bp, chat->shared_state.voice_state); // 8
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_state_bin(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 5);
|
||||
|
||||
bin_pack_bin(bp, chat->shared_state_sig, SIGNATURE_SIZE); // 1
|
||||
bin_pack_bin(bp, chat->shared_state.founder_public_key, EXT_PUBLIC_KEY_SIZE); // 2
|
||||
bin_pack_bin(bp, chat->shared_state.group_name, chat->shared_state.group_name_len); // 3
|
||||
bin_pack_bin(bp, chat->shared_state.password, chat->shared_state.password_length); // 4
|
||||
bin_pack_bin(bp, chat->shared_state.mod_list_hash, MOD_MODERATION_HASH_SIZE); // 5
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_topic_info(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 6);
|
||||
|
||||
bin_pack_u32(bp, chat->topic_info.version); // 1
|
||||
bin_pack_u16(bp, chat->topic_info.length); // 2
|
||||
bin_pack_u16(bp, chat->topic_info.checksum); // 3
|
||||
bin_pack_bin(bp, chat->topic_info.topic, chat->topic_info.length); // 4
|
||||
bin_pack_bin(bp, chat->topic_info.public_sig_key, SIG_PUBLIC_KEY_SIZE); // 5
|
||||
bin_pack_bin(bp, chat->topic_sig, SIGNATURE_SIZE); // 6
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_mod_list(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 2);
|
||||
|
||||
const uint16_t num_mods = min_u16(chat->moderation.num_mods, MOD_MAX_NUM_MODERATORS);
|
||||
|
||||
if (num_mods == 0) {
|
||||
bin_pack_u16(bp, num_mods); // 1
|
||||
bin_pack_nil(bp); // 2
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *packed_mod_list = (uint8_t *)malloc(num_mods * MOD_LIST_ENTRY_SIZE);
|
||||
|
||||
// we can still recover without the mod list
|
||||
if (packed_mod_list == nullptr) {
|
||||
bin_pack_u16(bp, 0); // 1
|
||||
bin_pack_nil(bp); // 2
|
||||
LOGGER_ERROR(chat->log, "Failed to allocate memory for moderation list");
|
||||
return;
|
||||
}
|
||||
|
||||
bin_pack_u16(bp, num_mods); // 1
|
||||
|
||||
mod_list_pack(&chat->moderation, packed_mod_list);
|
||||
|
||||
const size_t packed_size = num_mods * MOD_LIST_ENTRY_SIZE;
|
||||
|
||||
bin_pack_bin(bp, packed_mod_list, packed_size); // 2
|
||||
|
||||
free(packed_mod_list);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_keys(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 4);
|
||||
|
||||
bin_pack_bin(bp, chat->chat_public_key, EXT_PUBLIC_KEY_SIZE); // 1
|
||||
bin_pack_bin(bp, chat->chat_secret_key, EXT_SECRET_KEY_SIZE); // 2
|
||||
bin_pack_bin(bp, chat->self_public_key, EXT_PUBLIC_KEY_SIZE); // 3
|
||||
bin_pack_bin(bp, chat->self_secret_key, EXT_SECRET_KEY_SIZE); // 4
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_self_info(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 4);
|
||||
|
||||
const GC_Peer *self = &chat->group[0];
|
||||
|
||||
assert(self->nick_length <= MAX_GC_NICK_SIZE);
|
||||
|
||||
bin_pack_u16(bp, self->nick_length); // 1
|
||||
bin_pack_u08(bp, (uint8_t)self->role); // 2
|
||||
bin_pack_u08(bp, (uint8_t)self->status); // 3
|
||||
bin_pack_bin(bp, self->nick, self->nick_length); // 4
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void save_pack_saved_peers(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
bin_pack_array(bp, 2);
|
||||
|
||||
uint8_t *saved_peers = (uint8_t *)malloc(GC_MAX_SAVED_PEERS * GC_SAVED_PEER_SIZE);
|
||||
|
||||
// we can still recover without the saved peers list
|
||||
if (saved_peers == nullptr) {
|
||||
bin_pack_u16(bp, 0); // 1
|
||||
bin_pack_nil(bp); // 2
|
||||
LOGGER_ERROR(chat->log, "Failed to allocate memory for saved peers list");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t packed_size = 0;
|
||||
const int count = pack_gc_saved_peers(chat, saved_peers, GC_MAX_SAVED_PEERS * GC_SAVED_PEER_SIZE, &packed_size);
|
||||
|
||||
if (count < 0) {
|
||||
LOGGER_ERROR(chat->log, "Failed to pack saved peers");
|
||||
}
|
||||
|
||||
bin_pack_u16(bp, packed_size); // 1
|
||||
|
||||
if (packed_size == 0) {
|
||||
bin_pack_nil(bp); // 2
|
||||
free(saved_peers);
|
||||
return;
|
||||
}
|
||||
|
||||
bin_pack_bin(bp, saved_peers, packed_size); // 2
|
||||
|
||||
free(saved_peers);
|
||||
}
|
||||
|
||||
void gc_save_pack_group(const GC_Chat *chat, Bin_Pack *bp)
|
||||
{
|
||||
if (chat->numpeers == 0) {
|
||||
LOGGER_ERROR(chat->log, "Failed to pack group: numpeers is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
bin_pack_array(bp, 7);
|
||||
|
||||
save_pack_state_values(chat, bp); // 1
|
||||
save_pack_state_bin(chat, bp); // 2
|
||||
save_pack_topic_info(chat, bp); // 3
|
||||
save_pack_mod_list(chat, bp); // 4
|
||||
save_pack_keys(chat, bp); // 5
|
||||
save_pack_self_info(chat, bp); // 6
|
||||
save_pack_saved_peers(chat, bp); // 7
|
||||
}
|
35
external/toxcore/c-toxcore/toxcore/group_pack.h
vendored
Normal file
35
external/toxcore/c-toxcore/toxcore/group_pack.h
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2020 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Packer and unpacker functions for saving and loading groups.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_PACK_H
|
||||
#define GROUP_PACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bin_pack.h"
|
||||
#include "bin_unpack.h"
|
||||
#include "group_common.h"
|
||||
|
||||
/**
|
||||
* Packs group data from `chat` into `mp` in binary format. Parallel to the
|
||||
* `gc_load_unpack_group` function.
|
||||
*/
|
||||
non_null()
|
||||
void gc_save_pack_group(const GC_Chat *chat, Bin_Pack *bp);
|
||||
|
||||
/**
|
||||
* Unpacks binary group data from `obj` into `chat`. Parallel to the `gc_save_pack_group`
|
||||
* function.
|
||||
*
|
||||
* Return true if unpacking is successful.
|
||||
*/
|
||||
non_null()
|
||||
bool gc_load_unpack_group(GC_Chat *chat, Bin_Unpack *bu);
|
||||
|
||||
#endif // GROUP_PACK_H
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user