Compare commits

...

34 Commits

Author SHA1 Message Date
3567aba4db change cd output name 2023-10-15 16:40:48 +02:00
9b07cb4dce compile fixes for toxcore and gcc12 2023-10-15 16:34:07 +02:00
c89bba25a3 update toxcore dep, so clone works again 2023-10-15 15:57:26 +02:00
f9bc83811c properly handle broken info 2023-08-10 01:32:24 +02:00
5c4bb1aa42 update packet ids 2023-08-06 18:36:21 +02:00
2a143a4c2e remove extra include 2023-06-17 15:47:59 +02:00
3072d2936e fix connecting via chatid 2023-06-16 22:31:00 +02:00
7458841417 cd: switch to static deps 2023-06-16 20:21:10 +02:00
2b3ee3316a msvc fixes 2023-06-16 17:16:50 +02:00
622c9d9d96 add github cd 2023-06-16 16:55:26 +02:00
caa913fa51 small update 2023-06-16 02:05:27 +02:00
261c487cf2 update deps 2023-03-12 18:49:26 +01:00
086fc52e92 dynamic timeouts and minor cleanups 2023-03-12 01:26:23 +01:00
cd6141ee00 updated ft with experimental cca 2023-01-31 02:02:01 +01:00
5fa8dc712a actually use --ft_ options *facepalm* 2023-01-22 22:07:22 +01:00
e0d4c4d1e1 more strict sending 2023-01-22 17:21:03 +01:00
de247c9e91 actually set group name 2023-01-20 00:00:57 +01:00
20c41e1a02 tweak defaults, better peer connection state tracking (none :P) 2023-01-19 23:35:30 +01:00
613ae14530 fix chunk want duplicate hashes, outgoing requests are now prioritized torwards peers we get more data from 2023-01-19 19:43:00 +01:00
294a427eb0 ft filekind refactor + connection state drafting 2023-01-19 14:37:51 +01:00
9f8f681e18 actual time delta 2023-01-18 18:31:00 +01:00
365edc35e9 make incoming request timeout and respect a failed sendInit() 2023-01-18 01:52:39 +01:00
d888e91ada add support for variable chunk size, double 2023-01-18 00:47:08 +01:00
2e745b617d update readme 2023-01-17 22:25:18 +01:00
2f1bb3fac2 make max transfers configurable 2023-01-17 20:52:03 +01:00
92dcc81731 update tf with lossy and print up/down stats every 15s 2023-01-17 19:34:36 +01:00
83dcf2af82 update ft and tweaks 2023-01-17 17:52:27 +01:00
5d4108c3e6 improve readme 2023-01-17 16:06:20 +01:00
4ee1a865aa expose more parameters and refactor cl 2023-01-17 15:46:56 +01:00
65c6398369 barebones readme 2023-01-16 23:26:14 +01:00
c0187ae405 implement all the commandline parameters, add more, and plan for more 2023-01-16 23:20:37 +01:00
999ef20437 remote fixes 2023-01-16 17:09:12 +01:00
3b17fca6b2 license and typos 2023-01-16 16:53:58 +01:00
b74cc8f6bf fix queue order (properly sequential priority now) 2023-01-16 16:28:59 +01:00
26 changed files with 944 additions and 365 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: Green-Sky

43
.github/workflows/cd.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: ContinuousDelivery
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
BUILD_TYPE: Release
jobs:
windows:
timeout-minutes: 15
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Dependencies
run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static
# setup vs env
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: Configure CMake
run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
- uses: actions/upload-artifact@v3
with:
name: ${{ github.event.repository.name }}-windows-msvc-x86_64
# TODO: do propper packing
path: |
${{github.workspace}}/build/bin/

View File

@ -36,7 +36,7 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL
)
if (NOT WIN32)
link_libraries(-fsanitize=address,undefined)
#link_libraries(-fsanitize=address,undefined)
#link_libraries(-fsanitize=undefined)
endif()
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Erik Scholz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

63
README.md Normal file
View File

@ -0,0 +1,63 @@
# Tool to send and receive files using Tox NGC FileTransfers
currently on prototype FT1
## Example
### sender (seeder)
`$ tox_ngc_ft1_tool -F sender.tox -G <ngc_chat_id> -a sha1_info -f file_to_transfer`
this will print this tools tox_id and the generated info_hash
### receivers (leechers)
`$ tox_ngc_ft1_tool -F sender.tox -G <ngc_chat_id> -a sha1_info -D <info_hash>`
this will first download the info using the info_hash and then all the file chunks listed in the info
while simultaneously resharing allready downloaded chunks and info (swarming)
to increase the amount of parallel chunk down/up loads, you can increase the value with the -I and -O option. the default for -I is 32 and for -O 16, which are relatively low numbers, which in practice can get you up to ~700KiB/s.
## Usage
```
$ tox_ngc_ft1_tool
~~~ HELP ~~~
meta:
-v version info
-V verbose
-h help
connectivity:
-G <chat_id>
-F profile.tox
-N <self_name> (defaults to 'tox_ngc_ft1_tool')
will print friend id at startup
will autoaccept any invite
if no -F given, will not save profile.
if profile exists load, otherwise create new
transfer variant:
-a id1/sha1_single/sha1_info/sha2_single/sha2_info
send:
-f send_this_file.zip
receive:
-d dump/everything/in/this/dir
-D <id/hash> (what to dl)
!!! ADVANCED !!!
tox:
-L disable local discovery
-U disable udp
-P proxy_host proxy_port
-p tox_port (bind tox to that port)
FT1:
--ft_ack_per_packet
--ft_init_retry_timeout_after
--ft_sending_give_up_after
transfer logic:
-I <max_incoming_transfers>
-O <max_outgoing_transfers>
```

View File

@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
add_library(tox_ngc_ft1 STATIC
./tox_ngc_ft1/ngc_ft1.h
./tox_ngc_ft1/ngc_ft1.cpp
./tox_ngc_ft1/ledbat.hpp
./tox_ngc_ft1/ledbat.cpp
)
target_include_directories(tox_ngc_ft1 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/tox_ngc_ft1")

View File

@ -2,6 +2,198 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(./toxcore.cmake)
set(TOX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c-toxcore/")
# TODO: shared
add_library(toxcore STATIC
${TOX_DIR}third_party/cmp/cmp.c
${TOX_DIR}third_party/cmp/cmp.h
${TOX_DIR}toxcore/announce.c
${TOX_DIR}toxcore/announce.h
${TOX_DIR}toxcore/bin_pack.c
${TOX_DIR}toxcore/bin_pack.h
${TOX_DIR}toxcore/bin_unpack.c
${TOX_DIR}toxcore/bin_unpack.h
${TOX_DIR}toxcore/ccompat.c
${TOX_DIR}toxcore/ccompat.h
${TOX_DIR}toxcore/crypto_core.c
${TOX_DIR}toxcore/crypto_core.h
${TOX_DIR}toxcore/DHT.c
${TOX_DIR}toxcore/DHT.h
${TOX_DIR}toxcore/events/conference_connected.c
${TOX_DIR}toxcore/events/conference_invite.c
${TOX_DIR}toxcore/events/conference_message.c
${TOX_DIR}toxcore/events/conference_peer_list_changed.c
${TOX_DIR}toxcore/events/conference_peer_name.c
${TOX_DIR}toxcore/events/conference_title.c
${TOX_DIR}toxcore/events/events_alloc.c
${TOX_DIR}toxcore/events/events_alloc.h
${TOX_DIR}toxcore/events/file_chunk_request.c
${TOX_DIR}toxcore/events/file_recv.c
${TOX_DIR}toxcore/events/file_recv_chunk.c
${TOX_DIR}toxcore/events/file_recv_control.c
${TOX_DIR}toxcore/events/friend_connection_status.c
${TOX_DIR}toxcore/events/friend_lossless_packet.c
${TOX_DIR}toxcore/events/friend_lossy_packet.c
${TOX_DIR}toxcore/events/friend_message.c
${TOX_DIR}toxcore/events/friend_name.c
${TOX_DIR}toxcore/events/friend_read_receipt.c
${TOX_DIR}toxcore/events/friend_request.c
${TOX_DIR}toxcore/events/friend_status.c
${TOX_DIR}toxcore/events/friend_status_message.c
${TOX_DIR}toxcore/events/friend_typing.c
${TOX_DIR}toxcore/events/self_connection_status.c
#${TOX_DIR}toxcore/events/group_custom_packet.c
#${TOX_DIR}toxcore/events/group_custom_private_packet.c
#${TOX_DIR}toxcore/events/group_invite.c
#${TOX_DIR}toxcore/events/group_join_fail.c
#${TOX_DIR}toxcore/events/group_message.c
#${TOX_DIR}toxcore/events/group_moderation.c
#${TOX_DIR}toxcore/events/group_password.c
#${TOX_DIR}toxcore/events/group_peer_exit.c
#${TOX_DIR}toxcore/events/group_peer_join.c
#${TOX_DIR}toxcore/events/group_peer_limit.c
#${TOX_DIR}toxcore/events/group_peer_name.c
#${TOX_DIR}toxcore/events/group_peer_status.c
#${TOX_DIR}toxcore/events/group_privacy_state.c
#${TOX_DIR}toxcore/events/group_private_message.c
#${TOX_DIR}toxcore/events/group_self_join.c
#${TOX_DIR}toxcore/events/group_topic.c
#${TOX_DIR}toxcore/events/group_topic_lock.c
#${TOX_DIR}toxcore/events/group_voice_state.c
${TOX_DIR}toxcore/forwarding.c
${TOX_DIR}toxcore/forwarding.h
${TOX_DIR}toxcore/friend_connection.c
${TOX_DIR}toxcore/friend_connection.h
${TOX_DIR}toxcore/friend_requests.c
${TOX_DIR}toxcore/friend_requests.h
${TOX_DIR}toxcore/group.c
${TOX_DIR}toxcore/group.h
${TOX_DIR}toxcore/group_announce.c
${TOX_DIR}toxcore/group_announce.h
${TOX_DIR}toxcore/group_moderation.c
${TOX_DIR}toxcore/group_moderation.h
${TOX_DIR}toxcore/group_chats.c
${TOX_DIR}toxcore/group_chats.h
${TOX_DIR}toxcore/group_common.h
${TOX_DIR}toxcore/group_connection.c
${TOX_DIR}toxcore/group_connection.h
${TOX_DIR}toxcore/group_onion_announce.c
${TOX_DIR}toxcore/group_onion_announce.h
${TOX_DIR}toxcore/group_pack.c
${TOX_DIR}toxcore/group_pack.h
${TOX_DIR}toxcore/LAN_discovery.c
${TOX_DIR}toxcore/LAN_discovery.h
${TOX_DIR}toxcore/list.c
${TOX_DIR}toxcore/list.h
${TOX_DIR}toxcore/logger.c
${TOX_DIR}toxcore/logger.h
${TOX_DIR}toxcore/Messenger.c
${TOX_DIR}toxcore/Messenger.h
${TOX_DIR}toxcore/mem.c
${TOX_DIR}toxcore/mem.h
${TOX_DIR}toxcore/mono_time.c
${TOX_DIR}toxcore/mono_time.h
${TOX_DIR}toxcore/net_crypto.c
${TOX_DIR}toxcore/net_crypto.h
${TOX_DIR}toxcore/network.c
${TOX_DIR}toxcore/network.h
${TOX_DIR}toxcore/onion_announce.c
${TOX_DIR}toxcore/onion_announce.h
${TOX_DIR}toxcore/onion.c
${TOX_DIR}toxcore/onion_client.c
${TOX_DIR}toxcore/onion_client.h
${TOX_DIR}toxcore/onion.h
${TOX_DIR}toxcore/ping_array.c
${TOX_DIR}toxcore/ping_array.h
${TOX_DIR}toxcore/ping.c
${TOX_DIR}toxcore/ping.h
${TOX_DIR}toxcore/shared_key_cache.c
${TOX_DIR}toxcore/shared_key_cache.h
${TOX_DIR}toxcore/state.c
${TOX_DIR}toxcore/state.h
${TOX_DIR}toxcore/TCP_client.c
${TOX_DIR}toxcore/TCP_client.h
${TOX_DIR}toxcore/TCP_common.c
${TOX_DIR}toxcore/TCP_common.h
${TOX_DIR}toxcore/TCP_connection.c
${TOX_DIR}toxcore/TCP_connection.h
${TOX_DIR}toxcore/TCP_server.c
${TOX_DIR}toxcore/TCP_server.h
${TOX_DIR}toxcore/timed_auth.c
${TOX_DIR}toxcore/timed_auth.h
${TOX_DIR}toxcore/tox_api.c
${TOX_DIR}toxcore/tox.c
${TOX_DIR}toxcore/tox_dispatch.c
${TOX_DIR}toxcore/tox_dispatch.h
${TOX_DIR}toxcore/tox_events.c
${TOX_DIR}toxcore/tox_events.h
${TOX_DIR}toxcore/tox.h
${TOX_DIR}toxcore/tox_private.c
${TOX_DIR}toxcore/tox_private.h
${TOX_DIR}toxcore/tox_unpack.c
${TOX_DIR}toxcore/tox_unpack.h
${TOX_DIR}toxcore/util.c
${TOX_DIR}toxcore/util.h
)
# HACK: "install" api headers into self
# this is dirty, should be binary dir
# TODO: add the others
configure_file(
${TOX_DIR}toxcore/tox.h
${TOX_DIR}tox/tox.h
@ONLY
)
configure_file(
${TOX_DIR}toxcore/tox_events.h
${TOX_DIR}tox/tox_events.h
@ONLY
)
target_include_directories(toxcore PRIVATE "${TOX_DIR}toxcore")
target_include_directories(toxcore PUBLIC "${TOX_DIR}")
target_compile_definitions(toxcore PUBLIC USE_IPV6=1)
#target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_DEBUG)
target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_INFO)
find_package(unofficial-sodium CONFIG QUIET)
find_package(sodium QUIET)
if(unofficial-sodium_FOUND) # vcpkg
if(TARGET unofficial-sodium::sodium)
target_link_libraries(toxcore unofficial-sodium::sodium)
endif()
if(TARGET unofficial-sodium::sodium_config_public)
target_link_libraries(toxcore unofficial-sodium::sodium_config_public)
endif()
elseif(sodium_FOUND)
target_link_libraries(toxcore sodium)
else()
message(SEND_ERROR "missing libsodium")
endif()
if(WIN32)
target_link_libraries(toxcore ws2_32 iphlpapi)
endif()
find_package(pthreads QUIET)
if(TARGET PThreads4W::PThreads4W)
target_link_libraries(toxcore PThreads4W::PThreads4W)
else()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(toxcore Threads::Threads)
endif()
add_executable(DHT_Bootstrap EXCLUDE_FROM_ALL
${TOX_DIR}other/DHT_bootstrap.c
${TOX_DIR}other/bootstrap_node_packets.h
${TOX_DIR}other/bootstrap_node_packets.c
${TOX_DIR}testing/misc_tools.h
${TOX_DIR}testing/misc_tools.c
)
target_link_libraries(DHT_Bootstrap toxcore)

View File

@ -1,159 +0,0 @@
set(TOX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c-toxcore/")
# TODO: shared
add_library(toxcore STATIC
${TOX_DIR}third_party/cmp/cmp.c
${TOX_DIR}third_party/cmp/cmp.h
${TOX_DIR}toxcore/announce.c
${TOX_DIR}toxcore/announce.h
${TOX_DIR}toxcore/bin_pack.c
${TOX_DIR}toxcore/bin_pack.h
${TOX_DIR}toxcore/bin_unpack.c
${TOX_DIR}toxcore/bin_unpack.h
${TOX_DIR}toxcore/ccompat.c
${TOX_DIR}toxcore/ccompat.h
${TOX_DIR}toxcore/crypto_core.c
${TOX_DIR}toxcore/crypto_core.h
${TOX_DIR}toxcore/DHT.c
${TOX_DIR}toxcore/DHT.h
${TOX_DIR}toxcore/events/conference_connected.c
${TOX_DIR}toxcore/events/conference_invite.c
${TOX_DIR}toxcore/events/conference_message.c
${TOX_DIR}toxcore/events/conference_peer_list_changed.c
${TOX_DIR}toxcore/events/conference_peer_name.c
${TOX_DIR}toxcore/events/conference_title.c
${TOX_DIR}toxcore/events/events_alloc.c
${TOX_DIR}toxcore/events/events_alloc.h
${TOX_DIR}toxcore/events/file_chunk_request.c
${TOX_DIR}toxcore/events/file_recv.c
${TOX_DIR}toxcore/events/file_recv_chunk.c
${TOX_DIR}toxcore/events/file_recv_control.c
${TOX_DIR}toxcore/events/friend_connection_status.c
${TOX_DIR}toxcore/events/friend_lossless_packet.c
${TOX_DIR}toxcore/events/friend_lossy_packet.c
${TOX_DIR}toxcore/events/friend_message.c
${TOX_DIR}toxcore/events/friend_name.c
${TOX_DIR}toxcore/events/friend_read_receipt.c
${TOX_DIR}toxcore/events/friend_request.c
${TOX_DIR}toxcore/events/friend_status.c
${TOX_DIR}toxcore/events/friend_status_message.c
${TOX_DIR}toxcore/events/friend_typing.c
${TOX_DIR}toxcore/events/self_connection_status.c
${TOX_DIR}toxcore/forwarding.c
${TOX_DIR}toxcore/forwarding.h
${TOX_DIR}toxcore/friend_connection.c
${TOX_DIR}toxcore/friend_connection.h
${TOX_DIR}toxcore/friend_requests.c
${TOX_DIR}toxcore/friend_requests.h
${TOX_DIR}toxcore/group.c
${TOX_DIR}toxcore/group.h
${TOX_DIR}toxcore/group_announce.c
${TOX_DIR}toxcore/group_announce.h
${TOX_DIR}toxcore/group_moderation.c
${TOX_DIR}toxcore/group_moderation.h
${TOX_DIR}toxcore/group_chats.c
${TOX_DIR}toxcore/group_chats.h
${TOX_DIR}toxcore/group_common.h
${TOX_DIR}toxcore/group_connection.c
${TOX_DIR}toxcore/group_connection.h
${TOX_DIR}toxcore/group_onion_announce.c
${TOX_DIR}toxcore/group_onion_announce.h
${TOX_DIR}toxcore/group_pack.c
${TOX_DIR}toxcore/group_pack.h
${TOX_DIR}toxcore/LAN_discovery.c
${TOX_DIR}toxcore/LAN_discovery.h
${TOX_DIR}toxcore/list.c
${TOX_DIR}toxcore/list.h
${TOX_DIR}toxcore/logger.c
${TOX_DIR}toxcore/logger.h
${TOX_DIR}toxcore/Messenger.c
${TOX_DIR}toxcore/Messenger.h
${TOX_DIR}toxcore/mono_time.c
${TOX_DIR}toxcore/mono_time.h
${TOX_DIR}toxcore/net_crypto.c
${TOX_DIR}toxcore/net_crypto.h
${TOX_DIR}toxcore/network.c
${TOX_DIR}toxcore/network.h
${TOX_DIR}toxcore/onion_announce.c
${TOX_DIR}toxcore/onion_announce.h
${TOX_DIR}toxcore/onion.c
${TOX_DIR}toxcore/onion_client.c
${TOX_DIR}toxcore/onion_client.h
${TOX_DIR}toxcore/onion.h
${TOX_DIR}toxcore/ping_array.c
${TOX_DIR}toxcore/ping_array.h
${TOX_DIR}toxcore/ping.c
${TOX_DIR}toxcore/ping.h
${TOX_DIR}toxcore/shared_key_cache.c
${TOX_DIR}toxcore/shared_key_cache.h
${TOX_DIR}toxcore/state.c
${TOX_DIR}toxcore/state.h
${TOX_DIR}toxcore/TCP_client.c
${TOX_DIR}toxcore/TCP_client.h
${TOX_DIR}toxcore/TCP_common.c
${TOX_DIR}toxcore/TCP_common.h
${TOX_DIR}toxcore/TCP_connection.c
${TOX_DIR}toxcore/TCP_connection.h
${TOX_DIR}toxcore/TCP_server.c
${TOX_DIR}toxcore/TCP_server.h
${TOX_DIR}toxcore/timed_auth.c
${TOX_DIR}toxcore/timed_auth.h
${TOX_DIR}toxcore/tox_api.c
${TOX_DIR}toxcore/tox.c
${TOX_DIR}toxcore/tox_dispatch.c
${TOX_DIR}toxcore/tox_dispatch.h
${TOX_DIR}toxcore/tox_events.c
${TOX_DIR}toxcore/tox_events.h
${TOX_DIR}toxcore/tox.h
${TOX_DIR}toxcore/tox_private.c
${TOX_DIR}toxcore/tox_private.h
${TOX_DIR}toxcore/tox_unpack.c
${TOX_DIR}toxcore/tox_unpack.h
${TOX_DIR}toxcore/util.c
${TOX_DIR}toxcore/util.h
)
# HACK: "install" api headers into self
# this is dirty, should be binary dir
# TODO: add the others
configure_file(
${TOX_DIR}toxcore/tox.h
${TOX_DIR}tox/tox.h
@ONLY
)
target_include_directories(toxcore PRIVATE "${TOX_DIR}toxcore")
target_include_directories(toxcore PUBLIC "${TOX_DIR}")
target_compile_definitions(toxcore PUBLIC USE_IPV6=1)
#target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_DEBUG)
target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_INFO)
find_package(unofficial-sodium CONFIG QUIET)
find_package(sodium QUIET)
if(unofficial-sodium_FOUND) # vcpkg
target_link_libraries(toxcore unofficial-sodium::sodium unofficial-sodium::sodium_config_public)
elseif(sodium_FOUND)
target_link_libraries(toxcore sodium)
else()
message(SEND_ERROR "missing libsodium")
endif()
if(WIN32)
target_link_libraries(toxcore ws2_32 iphlpapi)
endif()
find_package(Threads REQUIRED)
target_link_libraries(toxcore Threads::Threads)
add_executable(DHT_Bootstrap EXCLUDE_FROM_ALL
${TOX_DIR}other/DHT_bootstrap.c
${TOX_DIR}other/bootstrap_node_packets.h
${TOX_DIR}other/bootstrap_node_packets.c
${TOX_DIR}testing/misc_tools.h
${TOX_DIR}testing/misc_tools.c
)
target_link_libraries(DHT_Bootstrap toxcore)

View File

@ -1,85 +1,135 @@
#include "./command_line.hpp"
#include <charconv>
#include <iostream>
#include <cassert>
#include <type_traits>
struct CLParser {
const size_t argc;
const char*const* argv;
size_t& i;
bool error {false};
bool parseFlag(std::string_view arg_sv, bool& flag) {
std::string_view arg0_sv{argv[i]};
if (arg0_sv != arg_sv) {
return false;
}
flag = true;
return true;
}
template<typename FN, typename Arg0, typename ...Args>
static void visit(FN&& fn, Arg0&& arg0, Args&& ...args) {
fn(arg0);
(fn(args),...);
}
template<typename Arg0, typename ...Args>
bool parseParam(std::string_view arg_sv, Arg0& arg0, Args& ...args) {
std::string_view arg0_sv{argv[i]};
if (arg0_sv != arg_sv) {
return false;
}
if (argc < 1+1+sizeof...(args)) {
std::cerr << "ERROR: " << arg_sv << " not enough parameters!\n\n";
error = true;
return true;
}
visit([this](auto& arg) {
if (error) return;
std::string_view argX_sv{argv[++i]};
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::string>) {
arg = argX_sv;
} else if constexpr (std::is_integral_v<T>) {
auto res = std::from_chars(argX_sv.data(), argX_sv.data()+argX_sv.size(), arg);
if (res.ptr != argX_sv.data() + argX_sv.size()) {
std::cerr << "ERROR: invalid parameter!\n\n";
error = true;
//PRINT_HELP_AND_BAIL;
}
} else if constexpr (std::is_same_v<T, float>) {
// HACK: wait for more charconv <.<
std::string tmp_str {argX_sv};
arg = std::stof(tmp_str);
} else {
assert(false && "invalid parameter type");
}
}, arg0, args...);
return true;
}
};
CommandLine::CommandLine(int argc, char** argv) {
assert(argc > 0);
exe = argv[0];
for (int i = 1; i < argc; i++) {
std::string_view arg_sv{argv[i]};
for (size_t i = 1; i < size_t(argc); i++) {
CLParser parser{size_t(argc), argv, i};
std::string_view arg_sv{argv[i]}; // alt
#define PRINT_HELP_AND_BAIL printHelp(); _should_exit = true; return;
if (arg_sv == "-v") {
version = true;
if (parser.parseFlag("-v", version)) {
_should_exit = true;
} else if (arg_sv == "-V") {
verbose = true;
} else if (parser.parseFlag("-V", verbose)) {
} else if (arg_sv == "-h") {
help = true;
printHelp();
_should_exit = true;
} else if (arg_sv == "-G") {
if (i+1 >= argc) {
std::cerr << "ERROR: -G missing <chat_id> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
chat_id = argv[++i];
} else if (arg_sv == "-F") {
if (i+1 >= argc) {
std::cerr << "ERROR: -F missing <path> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
profile_path = argv[++i];
} else if (arg_sv == "-N") {
if (i+1 >= argc) {
std::cerr << "ERROR: -N missing <self_name> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
self_name = argv[++i];
} else if (arg_sv == "-a") {
if (i+1 >= argc) {
std::cerr << "ERROR: -a missing <transfer_variant> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
std::string_view tv_sv{argv[++i]};
if (tv_sv == "id1") {
} else if (parser.parseParam("-G", chat_id)) {
} else if (parser.parseParam("-F", profile_path)) {
} else if (parser.parseParam("-N", self_name)) {
} else if (std::string tv; parser.parseParam("-a", tv)) {
if (tv == "id1") {
transfer_variant = TransferE::ID;
} else if (tv_sv == "sha1_single") {
} else if (tv == "sha1_single") {
transfer_variant = TransferE::SHA1_SINGLE;
} else if (tv_sv == "sha1_info") {
} else if (tv == "sha1_info") {
transfer_variant = TransferE::SHA1_INFO;
} else {
std::cerr << "ERROR: invalid <transfer_variant> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
} else if (arg_sv == "-f") {
if (i+1 >= argc) {
std::cerr << "ERROR: -f missing <path> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
send_path = argv[++i];
} else if (arg_sv == "-d") {
if (i+1 >= argc) {
std::cerr << "ERROR: -d missing <path> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
receive_dump_dir = argv[++i];
} else if (arg_sv == "-D") {
if (i+1 >= argc) {
std::cerr << "ERROR: -D missing <id/hash> parameter!\n\n";
PRINT_HELP_AND_BAIL;
}
receive_id = argv[++i];
} else if (parser.parseParam("-f", send_path)) {
} else if (parser.parseParam("-d", receive_dump_dir)) {
std::cout << "CL going to write to '" << receive_dump_dir << "'\n";
} else if (parser.parseParam("-D", receive_id)) {
} else if (parser.parseFlag("-L", tox_disable_local_discovery)) {
std::cout << "CL disabled local discovery\n";
} else if (parser.parseFlag("-U", tox_disable_udp)) {
std::cout << "CL disabled udp\n";
} else if (parser.parseParam("-P", proxy_host, proxy_port)) {
std::cout << "CL set proxy to " << proxy_host << proxy_port << "\n";
} else if (parser.parseParam("-p", tox_port)) {
std::cout << "CL set tox_port to " << tox_port << "\n";
} else if (parser.parseParam("--ft_ack_per_packet", ft_acks_per_packet)) {
} else if (parser.parseParam("--ft_init_retry_timeout_after", ft_init_retry_timeout_after)) {
} else if (parser.parseParam("--ft_sending_give_up_after", ft_sending_give_up_after)) {
} else if (parser.parseParam("-I", max_incoming_transfers)) {
} else if (parser.parseParam("-O", max_outgoing_transfers)) {
} else {
std::cerr << "ERROR: unknown parameter '" << arg_sv << "' !\n\n";
PRINT_HELP_AND_BAIL;
}
if (parser.error) {
PRINT_HELP_AND_BAIL;
}
}
if (transfer_variant == TransferE::INVALID) {
@ -102,7 +152,7 @@ void CommandLine::printHelp(void) {
<< " -N <self_name> (defaults to 'tox_ngc_ft1_tool')\n"
<< " will print friend id at startup\n"
<< " will autoaccept any invite\n"
<< " if no -F give, will not save profile.\n"
<< " if no -F given, will not save profile.\n"
<< " if profile exists load, otherwise create new\n"
<< "\n"
<< " transfer variant:\n"
@ -114,6 +164,22 @@ void CommandLine::printHelp(void) {
<< " receive:\n"
<< " -d dump/everything/in/this/dir\n"
<< " -D <id/hash> (what to dl)\n"
<< "\n"
<< "!!! ADVANCED !!!\n"
<< " tox:\n"
<< " -L disable local discovery\n"
<< " -U disable udp\n"
<< " -P proxy_host proxy_port\n"
<< " -p tox_port (bind tox to that port)\n"
<< "\n"
<< " FT1:\n"
<< " --ft_ack_per_packet\n"
<< " --ft_init_retry_timeout_after\n"
<< " --ft_sending_give_up_after\n"
<< "\n"
<< " transfer logic:\n"
<< " -I <max_incoming_transfers>\n"
<< " -O <max_outgoing_transfers>\n"
;
}

View File

@ -2,30 +2,6 @@
#include <string>
// meta:
// -v version info
// -V verbose
// -h help
//
// connectivity:
// -G <chat_id>
// -F profile.tox
// -N <self_name>
// will print friend id at startup
// will autoaccept any invite
// if no -F give, will not save profile.
// if profile exists load, otherwise create new
//
// transfer variant:
// -a id1/sha1_single/sha1_info/sha2_single/sha2_info
//
// send:
// -f send_this_file.zip
//
// receive:
// -d dump/everything/in/this/dir
// -D <id/hash> (what to dl)
enum class TransferE {
INVALID,
@ -68,6 +44,35 @@ struct CommandLine {
// -D <id/hash> (what to dl)
std::string receive_id;
// advanced tox:
// -L disable local discovery
bool tox_disable_local_discovery {false};
// -U disable udp (why?)
bool tox_disable_udp {false};
// -P proxy_host proxy_port
std::string proxy_host;
uint16_t proxy_port {0};
// -p port (start and end is set to the same port)
uint16_t tox_port {0};
// advanced FT1:
// --ft_ack_per_packet
size_t ft_acks_per_packet {3};
// --ft_init_retry_timeout_after
float ft_init_retry_timeout_after {5.f};
// --ft_sending_give_up_after
float ft_sending_give_up_after {30.f};
// ---- TODO ----
// advaced dl:
// -I max_incoming_transfers
size_t max_incoming_transfers {32};
// -O max_outgoing_transfers
size_t max_outgoing_transfers {8};
// -u request chunks only from UDP-direct peers
bool request_only_from_udp_peer {false};
CommandLine(int argc, char** argv);
void printHelp(void);

View File

@ -54,20 +54,28 @@ std::vector<uint8_t> FTInfoSHA1::toBuffer(void) const {
}
assert(buffer.size() == 256+8);
// chunk size?
// chunk size
{ // HACK: endianess
buffer.push_back((chunk_size>>(0*8)) & 0xff);
buffer.push_back((chunk_size>>(1*8)) & 0xff);
buffer.push_back((chunk_size>>(2*8)) & 0xff);
buffer.push_back((chunk_size>>(3*8)) & 0xff);
}
assert(buffer.size() == 256+8+4);
for (const auto& chunk : chunks) {
for (size_t i = 0; i < chunk.data.size(); i++) {
buffer.push_back(chunk.data[i]);
}
}
assert(buffer.size() == 256+8+20*chunks.size());
assert(buffer.size() == 256+8+4+20*chunks.size());
return buffer;
}
void FTInfoSHA1::fromBuffer(const std::vector<uint8_t>& buffer) {
assert(buffer.size() >= 256+8);
assert(buffer.size() >= 256+8+4);
// TODO: optimize
file_name.clear();
@ -91,9 +99,17 @@ void FTInfoSHA1::fromBuffer(const std::vector<uint8_t>& buffer) {
file_size |= uint64_t(buffer[256+7]) << (7*8);
}
assert((buffer.size()-(256+8)) % 20 == 0);
{ // HACK: endianess
chunk_size = 0;
chunk_size |= uint32_t(buffer[256+8+0]) << (0*8);
chunk_size |= uint32_t(buffer[256+8+1]) << (1*8);
chunk_size |= uint32_t(buffer[256+8+2]) << (2*8);
chunk_size |= uint32_t(buffer[256+8+3]) << (3*8);
}
for (size_t offset = 256+8; offset < buffer.size();) {
assert((buffer.size()-(256+8+4)) % 20 == 0);
for (size_t offset = 256+8+4; offset < buffer.size();) {
assert(buffer.size() >= offset + 20);
auto& chunk = chunks.emplace_back();
@ -107,6 +123,7 @@ void FTInfoSHA1::fromBuffer(const std::vector<uint8_t>& buffer) {
std::ostream& operator<<(std::ostream& out, const FTInfoSHA1& v) {
out << " file_name: " << v.file_name << "\n";
out << " file_size: " << v.file_size << "\n";
out << " chunk_size: " << v.chunk_size << "\n";
out << " chunks.size(): " << v.chunks.size() << "\n";
return out;
}

View File

@ -43,12 +43,23 @@ namespace std { // inject
struct FTInfoSHA1 {
std::string file_name;
uint64_t file_size {0};
static constexpr size_t chunk_size {64*1024}; // 64KiB for now
uint32_t chunk_size {128*1024}; // 128KiB for now
std::vector<SHA1Digest> chunks;
std::vector<uint8_t> toBuffer(void) const;
void fromBuffer(const std::vector<uint8_t>& buffer);
};
std::ostream& operator<<(std::ostream& out, const FTInfoSHA1& v);
// TODO: use
struct FTInfoSHA1v2 {
std::vector<std::string> file_names;
uint64_t file_size {0};
uint32_t chunk_size {128*1024}; // 128KiB for now
std::vector<SHA1Digest> chunks;
std::vector<uint8_t> toBuffer(void) const;
void fromBuffer(const std::vector<uint8_t>& buffer);
};
std::ostream& operator<<(std::ostream& out, const FTInfoSHA1& v);

View File

@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <vector>
// returns the 20bytes sha1 hash

View File

@ -20,7 +20,7 @@
namespace States {
ReceiveStartSHA1::ReceiveStartSHA1(ToxClient& tcl, const CommandLine& cl) : StateI(tcl) {
ReceiveStartSHA1::ReceiveStartSHA1(ToxClient& tcl, const CommandLine& cl) : StateI(tcl), _cl(cl), _dump_dir(cl.receive_dump_dir) {
if (cl.receive_id.empty()) {
throw std::runtime_error("receiver missing id");
}
@ -41,14 +41,13 @@ bool ReceiveStartSHA1::iterate(float delta) {
// timout if not heard after 10s
if (time_since_remote_activity >= 10.f) {
std::cerr << "ReceiveStartSHA1 info tansfer timed out " << std::get<0>(*_transfer) << ":" << std::get<1>(*_transfer) << "." << std::get<2>(*_transfer) << "\n";
std::cerr << "ReceiveStartSHA1 info tansfer timed out " << std::get<0>(*_transfer) << ":" << std::get<1>(*_transfer) << "." << int(std::get<2>(*_transfer)) << "\n";
_transfer.reset();
}
} else if (_time_since_last_request >= 15.f) { // blast ever 15sec
_time_since_last_request = 0.f;
// TODO: select random and try, not blas
// ... and we are blasing
_tcl.forEachGroup([this](const uint32_t group_number) {
_tcl.forEachGroupPeer(group_number, [this, group_number](uint32_t peer_number) {
_tcl.sendFT1RequestPrivate(
@ -56,13 +55,17 @@ bool ReceiveStartSHA1::iterate(float delta) {
NGC_FT1_file_kind::HASH_SHA1_INFO,
_sha1_info_hash.data.data(), _sha1_info_hash.size()
);
std::cout << "ReceiveStartSHA1 sendig info request to " << group_number << ":" << peer_number << "\n";
std::cout
<< "ReceiveStartSHA1 sendig info request to "
<< group_number << ":" << peer_number
<< " over " << (_tcl.getGroupPeerConnectionStatus(group_number, peer_number) == Tox_Connection::TOX_CONNECTION_TCP ? "tcp" : "udp")
<< "\n"
;
});
});
}
// if not transfer, request from random peer (equal dist!!)
// TODO: return true if done
return _done;
}
@ -72,38 +75,49 @@ std::unique_ptr<StateI> ReceiveStartSHA1::nextState(void) {
std::cout << "ReceiveStartSHA1 info is: \n" << sha1_info;
bool file_existed = std::filesystem::exists(sha1_info.file_name);
auto file_path = std::filesystem::path{_dump_dir} / sha1_info.file_name;
bool file_existed = std::filesystem::exists(file_path);
if (!file_existed) {
std::ofstream(sha1_info.file_name) << '\0'; // create the file
if (!_dump_dir.empty()) {
std::filesystem::create_directories(_dump_dir);
}
std::filesystem::resize_file(sha1_info.file_name, sha1_info.file_size);
std::ofstream(file_path) << '\0'; // create the file
}
std::filesystem::resize_file(file_path, sha1_info.file_size);
// open file for writing (pre allocate?)
std::error_code err;
mio::mmap_sink file_map = mio::make_mmap_sink(sha1_info.file_name, 0, sha1_info.file_size, err);
mio::mmap_sink file_map = mio::make_mmap_sink(file_path.string(), 0, sha1_info.file_size, err);
std::vector<bool> have_chunk(sha1_info.chunks.size(), false);
// dont overwrite correct existing data
if (file_existed) {
std::cout << "ReceiveStartSHA1 checking existing file\n";
size_t f_i = 0;
for (size_t c_i = 0; f_i + FTInfoSHA1::chunk_size < file_map.length(); f_i += FTInfoSHA1::chunk_size, c_i++) {
if (sha1_info.chunks[c_i] == hash_sha1(file_map.data()+f_i, FTInfoSHA1::chunk_size)) {
size_t f_i {0};
size_t tmp_have_count {0};
for (size_t c_i = 0; f_i + sha1_info.chunk_size < file_map.length(); f_i += sha1_info.chunk_size, c_i++) {
if (sha1_info.chunks[c_i] == hash_sha1(file_map.data()+f_i, sha1_info.chunk_size)) {
have_chunk[c_i] = true;
tmp_have_count++;
}
}
if (f_i < file_map.length()) {
if (sha1_info.chunks.back() == hash_sha1(file_map.data()+f_i, file_map.length()-f_i)) {
have_chunk.back() = true;
tmp_have_count++;
}
}
std::cout << "ReceiveStartSHA1 have " << tmp_have_count << "/" << sha1_info.chunks.size() << " chunks (" << float(tmp_have_count)/sha1_info.chunks.size() * 100.f << "%)\n";
}
std::cout << "ReceiveStartSHA1 switching state to SHA1\n";
return std::make_unique<SHA1>(
_tcl,
_cl,
std::move(file_map),
std::move(sha1_info),
std::move(_sha1_info_data),
@ -132,13 +146,13 @@ bool ReceiveStartSHA1::onFT1ReceiveInitSHA1Info(uint32_t group_number, uint32_t
if (_transfer.has_value()) {
// TODO: log?
return false; // allready in progress
return false; // already in progress
}
_sha1_info_data.resize(file_size);
_transfer = std::make_tuple(group_number, peer_number, transfer_id, 0.f);
std::cout << "ReceiveStartSHA1 accepted info transfer" << group_number << ":" << peer_number << "." << transfer_id << "\n";
std::cout << "ReceiveStartSHA1 accepted info transfer " << group_number << ":" << peer_number << "." << int(transfer_id) << "\n";
// accept
return true;
@ -162,12 +176,12 @@ void ReceiveStartSHA1::onFT1ReceiveDataSHA1Info(uint32_t group_number, uint32_t
std::cerr << "ReceiveStartSHA1 received info's hash does not match!, discarding\n";
_transfer.reset();
_sha1_info_data.clear();
}
std::cout << "ReceiveStartSHA1 info tansfer finished " << group_number << ":" << peer_number << "." << transfer_id << "\n";
} else {
std::cout << "ReceiveStartSHA1 info tansfer finished " << group_number << ":" << peer_number << "." << int(transfer_id) << "\n";
_done = true;
}
}
}
void ReceiveStartSHA1::onFT1SendDataSHA1Info(uint32_t, uint32_t, uint8_t, size_t, uint8_t*, size_t) {
// we cant send what we dont have

View File

@ -33,6 +33,9 @@ struct ReceiveStartSHA1 final : public StateI {
void onFT1SendDataSHA1Chunk(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, size_t data_offset, uint8_t* data, size_t data_size) override;
private:
const CommandLine& _cl;
std::string _dump_dir;
//FTInfoSHA1 _sha1_info;
std::vector<uint8_t> _sha1_info_data;
SHA1Digest _sha1_info_hash; // treat as const

View File

@ -17,7 +17,7 @@
namespace States {
SendStartSHA1::SendStartSHA1(ToxClient& tcl, const CommandLine& cl) : StateI(tcl), _file_path(cl.send_path) {
SendStartSHA1::SendStartSHA1(ToxClient& tcl, const CommandLine& cl) : StateI(tcl), _cl(cl), _file_path(cl.send_path) {
std::cout << "SendStartSHA1 start building sha1_info\n";
std::error_code err;
_file_map = mio::make_mmap_source(cl.send_path, 0, mio::map_entire_file, err);
@ -29,11 +29,12 @@ SendStartSHA1::SendStartSHA1(ToxClient& tcl, const CommandLine& cl) : StateI(tcl
// build info
_sha1_info.file_name = std::filesystem::path(cl.send_path).filename().string();
_sha1_info.file_size = _file_map.length();
//_sha1_info.chunk_size;
{ // build chunks
size_t i = 0;
for (; i + FTInfoSHA1::chunk_size < _file_map.length(); i += FTInfoSHA1::chunk_size) {
_sha1_info.chunks.push_back(hash_sha1(_file_map.data()+i, FTInfoSHA1::chunk_size));
for (; i + _sha1_info.chunk_size < _file_map.length(); i += _sha1_info.chunk_size) {
_sha1_info.chunks.push_back(hash_sha1(_file_map.data()+i, _sha1_info.chunk_size));
}
if (i < _file_map.length()) {
@ -72,6 +73,7 @@ std::unique_ptr<StateI> SendStartSHA1::nextState(void) {
// we are done setting up
return std::make_unique<SHA1>(
_tcl,
_cl,
std::move(new_file_map),
std::move(_sha1_info),
std::move(_sha1_info_data),

View File

@ -33,6 +33,8 @@ struct SendStartSHA1 final : public StateI {
void onFT1SendDataSHA1Chunk(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, size_t data_offset, uint8_t* data, size_t data_size) override;
private:
const CommandLine& _cl;
std::string _file_path;
mio::mmap_source _file_map;
FTInfoSHA1 _sha1_info;

View File

@ -4,13 +4,16 @@
#include "../hash_utils.hpp"
#include <algorithm>
#include <iostream>
#include <tuple>
#include <random>
namespace States {
SHA1::SHA1(
ToxClient& tcl,
const CommandLine& cl,
mio::mmap_sink&& file_map,
const FTInfoSHA1&& sha1_info,
const std::vector<uint8_t>&& sha1_info_data,
@ -27,6 +30,16 @@ SHA1::SHA1(
{
assert(_have_chunk.size() == _sha1_info.chunks.size());
_udp_only = cl.request_only_from_udp_peer;
_max_concurrent_in = cl.max_incoming_transfers;
_max_concurrent_out = cl.max_outgoing_transfers;
// build lookup table
for (size_t i = _sha1_info.chunks.size(); i > 0; i--) {
// chunks can have more then 1 index ..., for now, build reverse and have the first index be the real index
_chunk_hash_to_index[_sha1_info.chunks.at(i-1)] = i-1;
}
_have_all = true;
_have_count = 0;
for (size_t i = 0; i < _have_chunk.size(); i++) {
@ -34,15 +47,24 @@ SHA1::SHA1(
_have_count++;
} else {
_have_all = false;
// avoid same chunk hash dups
if (_chunk_hash_to_index.at(_sha1_info.chunks.at(i)) == i) {
_chunk_want_queue.push_back(i);
}
}
}
if (!_have_all) {
assert(_chunk_want_queue.size() > 0);
{ // load last chunk first :)
size_t tmp = _chunk_want_queue.back();
_chunk_want_queue.push_front(tmp);
_chunk_want_queue.pop_back();
}
// if not sequential, shuffle _chunk_want_queue
// build lookup table
for (size_t i = 0; i < _sha1_info.chunks.size(); i++) {
_chunk_hash_to_index[_sha1_info.chunks[i]] = i;
}
}
@ -82,7 +104,7 @@ bool SHA1::iterate(float delta) {
// if we have not heard for 10sec, timeout
if (time_since_remove_activity >= 10.f) {
std::cerr << "SHA1 receiving chunk tansfer timed out " << std::get<0>(*it) << ":" << std::get<1>(*it) << "." << int(std::get<2>(*it)) << "\n";
_chunk_want_queue.push_back(std::get<4>(*it)); // put it back
_chunk_want_queue.push_front(std::get<4>(*it)); // put it back
it = _transfers_receiving_chunk.erase(it);
} else {
it++;
@ -94,12 +116,24 @@ bool SHA1::iterate(float delta) {
// if we have not heard for 15sec, timeout
if (it->second >= 15.f) {
_chunk_want_queue.push_back(it->first); // put it back
_chunk_want_queue.push_front(it->first); // put it back
it = _chunks_requested.erase(it);
} else {
it++;
}
}
// queued requests
for (auto it = _queue_requested_chunk.begin(); it != _queue_requested_chunk.end();) {
float& timer = std::get<float>(*it);
timer += delta;
if (timer >= 10.f) {
it = _queue_requested_chunk.erase(it);
} else {
it++;
}
}
}
// if we have not reached the total cap for transfers
@ -111,16 +145,16 @@ bool SHA1::iterate(float delta) {
// send init to _queue_requested_info
const auto [group_number, peer_number] = _queue_requested_info.front();
if (_tcl.getGroupPeerConnectionStatus(group_number, peer_number) != TOX_CONNECTION_NONE) {
uint8_t transfer_id {0};
_tcl.sendFT1InitPrivate(
if (_tcl.sendFT1InitPrivate(
group_number, peer_number,
NGC_FT1_file_kind::HASH_SHA1_INFO,
_sha1_info_hash.data.data(), _sha1_info_hash.size(), // id (info hash)
_sha1_info_data.size(), // "file_size"
transfer_id
);
)) {
_transfers_requested_info.push_back({
group_number, peer_number,
transfer_id,
@ -128,22 +162,28 @@ bool SHA1::iterate(float delta) {
});
_queue_requested_info.pop_front();
}
}
} else if (!_queue_requested_chunk.empty()) { // then check for chunk requests
const auto [group_number, peer_number, chunk_hash] = _queue_requested_chunk.front();
const auto [group_number, peer_number, chunk_hash, _] = _queue_requested_chunk.front();
if (_tcl.getGroupPeerConnectionStatus(group_number, peer_number) != TOX_CONNECTION_NONE) {
if (!chunkIndex(chunk_hash).has_value()) {
std::cerr << "!chunkIndex(chunk_hash).has_value()\n";
exit(1);
}
size_t chunk_index = chunkIndex(chunk_hash).value();
size_t chunk_file_size = chunkSize(chunk_index);
uint8_t transfer_id {0};
_tcl.sendFT1InitPrivate(
if (_tcl.sendFT1InitPrivate(
group_number, peer_number,
NGC_FT1_file_kind::HASH_SHA1_CHUNK,
chunk_hash.data.data(), chunk_hash.size(), // id (chunk hash)
chunk_file_size,
transfer_id
);
)) {
_transfers_sending_chunk.push_back({
group_number, peer_number,
transfer_id,
@ -154,32 +194,119 @@ bool SHA1::iterate(float delta) {
_queue_requested_chunk.pop_front();
}
}
}
}
if (!_have_all && !_chunk_want_queue.empty() && _chunks_requested.size() + _transfers_receiving_chunk.size() < _max_concurrent_in) {
// update speeds and targets
_peer_speed_mesurement_interval_timer += delta;
if (_peer_speed_mesurement_interval_timer >= _peer_speed_mesurement_interval) {
_peer_speed_mesurement_interval_timer = 0.f; // we lose some time here, but precision is not the issue
_peer_in_bytes_array_index = (_peer_in_bytes_array_index + 1) % _peer_speed_mesurement_interval_count;
//for (const auto& [peer, array] : _peer_in_bytes_array) {
for (auto it = _peer_in_bytes_array.begin(); it != _peer_in_bytes_array.end();) {
const auto& [peer, array] = *it;
float avg {0.f};
for (size_t i = 0; i < array.size(); i++) {
avg += array[i];
}
if (avg == 0.f || _tcl.getGroupPeerConnectionStatus(peer.first, peer.second) == Tox_Connection::TOX_CONNECTION_NONE) {
_peer_in_speed.erase(peer);
it = _peer_in_bytes_array.erase(it);
continue;
}
// if 6 mesurment every 0.5sec -> avg is over 3sec -> /3 for /s
avg /= _peer_speed_mesurement_interval * _peer_speed_mesurement_interval_count;
// reset byte count for next round
_peer_in_bytes_array[peer][_peer_in_bytes_array_index] = 0;
_peer_in_speed[peer] = avg;
it++;
}
_peer_in_targets.clear();
_tcl.forEachGroup([this](uint32_t group_number) {
_tcl.forEachGroupPeer(group_number, [group_number, this](uint32_t peer_number) {
if (!_udp_only || _tcl.getGroupPeerConnectionStatus(group_number, peer_number) == Tox_Connection::TOX_CONNECTION_UDP) {
_peer_in_targets.push_back({group_number, peer_number});
}
});
});
if (!_peer_in_targets.empty()) {
std::vector<double> weights;
for (const auto& peer : _peer_in_targets) {
if (_peer_in_speed.count(peer)) {
weights.push_back(
std::clamp(
(_peer_in_speed.at(peer) / 1024.f) // KiB/s
* (20.f/500.f), // map to a range from 0 to 20, max at 500KiB/s
1.f,
20.f
)
);
} else {
weights.push_back(1.f);
}
}
std::discrete_distribution<size_t> tmp_dist{weights.cbegin(), weights.cend()};
_peer_in_targets_dist.param(tmp_dist.param());
}
}
if (!_have_all && !_peer_in_targets.empty() && !_chunk_want_queue.empty() && _chunks_requested.size() + _transfers_receiving_chunk.size() < _max_concurrent_in) {
// send out request, no burst tho
std::vector<std::pair<uint32_t, uint32_t>> target_peers;
_tcl.forEachGroup([&target_peers, this](uint32_t group_number) {
_tcl.forEachGroupPeer(group_number, [&target_peers, group_number](uint32_t peer_number) {
target_peers.push_back({group_number, peer_number});
});
});
uint32_t group_number;
uint32_t peer_number;
if (!target_peers.empty()) {
//if (_distrib.max() != target_peers.size()) {
//std::uniform_int_distribution<size_t> new_dist{0, target_peers.size()-1};
//_distrib.param(new_dist.param());
//}
//size_t target_index = _distrib(_rng);
size_t target_index = _rng()%target_peers.size();
auto [group_number, peer_number] = target_peers.at(target_index);
//size_t target_index = _rng()%target_peers.size();
size_t target_index = _peer_in_targets_dist(_rng);
std::tie(group_number, peer_number) = _peer_in_targets.at(target_index);
size_t chunk_index = _chunk_want_queue.front();
_chunks_requested[chunk_index] = 0.f;
_chunk_want_queue.pop_front();
_tcl.sendFT1RequestPrivate(group_number, peer_number, NGC_FT1_file_kind::HASH_SHA1_CHUNK, _sha1_info.chunks[chunk_index].data.data(), 20);
//std::cout << "sent request " << group_number << ":" << peer_number << "\n";
}
// log
_io_log_timer += delta;
static const float log_interval {10.f};
if (_io_log_timer >= log_interval) {
_io_log_timer = 0.f;
size_t bytes_up_since {_bytes_up - _bytes_up_last_log};
_bytes_up_last_log = _bytes_up;
size_t bytes_down_since {_bytes_down - _bytes_down_last_log};
_bytes_down_last_log = _bytes_down;
float up_kibs {(bytes_up_since / 1024.f) / log_interval};
float down_kibs {(bytes_down_since / 1024.f) / log_interval};
std::cout << std::string(40, '-') << "\n";
std::cout << "SHA1 speed down: " << down_kibs << "KiB/s up: " << up_kibs << "KiB/s\n";
std::cout << "SHA1 total down: " << _bytes_down / 1024 << "KiB up: " << _bytes_up / 1024 << "KiB\n";
std::cout << "SHA1 cwq:" << _chunk_want_queue.size() << " cwqr:" << _chunks_requested.size() << " trc:" << _transfers_receiving_chunk.size() << " tsc:" << _transfers_sending_chunk.size() << "\n";
std::cout << "SHA1 peer down speeds:\n";
for (const auto& [peer, speed] : _peer_in_speed) {
std::cout
<< " " << peer.first << ":" << peer.second
<< " " << (_tcl.getGroupPeerConnectionStatus(peer.first, peer.second) == Tox_Connection::TOX_CONNECTION_TCP ? "tcp" : "udp")
<< " (" << _tcl.getGroupPeerName(peer.first, peer.second) << ")"
<< " " << speed / 1024.f << "KiB/s\n"
;
}
std::cout << std::string(40, '-') << "\n";
}
// TODO: unmap and remap the file every couple of minutes to keep ram usage down?
@ -220,7 +347,7 @@ bool SHA1::onFT1ReceiveInitSHA1Info(uint32_t, uint32_t, const uint8_t*, size_t,
void SHA1::onFT1ReceiveDataSHA1Info(uint32_t, uint32_t, uint8_t, size_t, const uint8_t*, size_t) {
// no, in this state we have init
assert(false && "ft should have said dropped this for us!");
assert(false && "ft should have dropped this for us!");
}
void SHA1::onFT1SendDataSHA1Info(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, size_t data_offset, uint8_t* data, size_t data_size) {
@ -246,7 +373,7 @@ void SHA1::onFT1SendDataSHA1Info(uint32_t group_number, uint32_t peer_number, ui
// this transfer is "done" (ft still could have to retransfer)
for (auto it = _transfers_requested_info.cbegin(); it != _transfers_requested_info.cend(); it++) {
if (std::get<0>(*it) == group_number && std::get<1>(*it) == peer_number && std::get<2>(*it) == transfer_id) {
std::cout << "SHA1 info tansfer finished " << std::get<0>(*it) << ":" << std::get<1>(*it) << "." << std::get<2>(*it) << "\n";
std::cout << "SHA1 info tansfer finished " << std::get<0>(*it) << ":" << std::get<1>(*it) << "." << int(std::get<2>(*it)) << "\n";
_transfers_requested_info.erase(it);
break;
}
@ -284,7 +411,7 @@ bool SHA1::onFT1ReceiveInitSHA1Chunk(uint32_t group_number, uint32_t peer_number
SHA1Digest incomming_hash(file_id, file_id_size);
if (haveChunk(incomming_hash)) {
std::cout << "SHA1 ignoring init for chunk we allready have " << incomming_hash << "\n";
std::cout << "SHA1 ignoring init for chunk we already have " << incomming_hash << "\n";
return false;
}
@ -300,7 +427,7 @@ bool SHA1::onFT1ReceiveInitSHA1Chunk(uint32_t group_number, uint32_t peer_number
// check transfers
for (const auto& it : _transfers_receiving_chunk) {
if (std::get<4>(it) == chunk_index) {
// allready in transition
// already in transition
return false;
}
}
@ -324,6 +451,10 @@ void SHA1::onFT1ReceiveDataSHA1Chunk(uint32_t group_number, uint32_t peer_number
// check transfers
for (auto it = _transfers_receiving_chunk.begin(); it != _transfers_receiving_chunk.end(); it++) {
if (std::get<0>(*it) == group_number && std::get<1>(*it) == peer_number && std::get<2>(*it) == transfer_id) {
_bytes_down += data_size;
_peer_in_bytes_array[std::make_pair(group_number, peer_number)][_peer_in_bytes_array_index] += data_size;
std::get<float>(*it) = 0.f; // time
const size_t chunk_index = std::get<4>(*it);
@ -343,7 +474,9 @@ void SHA1::onFT1ReceiveDataSHA1Chunk(uint32_t group_number, uint32_t peer_number
SHA1Digest test_hash = hash_sha1(_file_map.data()+file_offset, chunk_file_size);
if (test_hash != _sha1_info.chunks[chunk_index]) {
std::cerr << "SHA1 received chunks's hash does not match!, discarding\n";
_bytes_down -= chunk_file_size; // penalize wrong data
_transfers_receiving_chunk.erase(it);
_chunk_want_queue.push_front(chunk_index); // put back in queue
break;
}
@ -363,6 +496,8 @@ void SHA1::onFT1SendDataSHA1Chunk(uint32_t group_number, uint32_t peer_number, u
// TODO: sub optimal
for (auto it = _transfers_sending_chunk.begin(); it != _transfers_sending_chunk.end(); it++) {
if (std::get<0>(*it) == group_number && std::get<1>(*it) == peer_number && std::get<2>(*it) == transfer_id) {
_bytes_up += data_size;
std::get<float>(*it) = 0.f; // time
const size_t chunk_index = std::get<4>(*it);
@ -388,14 +523,14 @@ void SHA1::onFT1SendDataSHA1Chunk(uint32_t group_number, uint32_t peer_number, u
void SHA1::queueUpRequestInfo(uint32_t group_number, uint32_t peer_number) {
// check ongoing transfers for dup
for (const auto& it : _transfers_requested_info) {
// if allready in queue
// if already in queue
if (std::get<0>(it) == group_number && std::get<1>(it) == peer_number) {
return;
}
}
for (auto& [i_g, i_p] : _queue_requested_info) {
// if allready in queue
// if already in queue
if (i_g == group_number && i_p == peer_number) {
return;
}
@ -408,15 +543,17 @@ void SHA1::queueUpRequestInfo(uint32_t group_number, uint32_t peer_number) {
void SHA1::queueUpRequestChunk(uint32_t group_number, uint32_t peer_number, const SHA1Digest& hash) {
// TODO: transfers
for (auto& [i_g, i_p, i_h] : _queue_requested_chunk) {
// if allready in queue
for (auto& [i_g, i_p, i_h, i_t] : _queue_requested_chunk) {
// if already in queue
if (i_g == group_number && i_p == peer_number && i_h == hash) {
// update timer
i_t = 0.f;
return;
}
}
// not in queue yet
_queue_requested_chunk.push_back(std::make_tuple(group_number, peer_number, hash));
_queue_requested_chunk.push_back(std::make_tuple(group_number, peer_number, hash, 0.f));
}
std::optional<size_t> SHA1::chunkIndex(const SHA1Digest& hash) const {

View File

@ -3,11 +3,13 @@
#include "../state.hpp"
#include "../ft_sha1_info.hpp"
#include "../command_line.hpp"
#include <mio/mio.hpp>
#include <unordered_map>
#include <map>
#include <optional>
#include <vector>
#include <deque>
#include <random>
@ -20,6 +22,7 @@ struct SHA1 final : public StateI {
public: // general interface
SHA1(
ToxClient& tcl,
const CommandLine& cl,
mio::mmap_sink&& file_map,
const FTInfoSHA1&& sha1_info,
const std::vector<uint8_t>&& sha1_info_data,
@ -55,12 +58,24 @@ struct SHA1 final : public StateI {
size_t chunkSize(size_t chunk_index) const;
bool haveChunk(const SHA1Digest& hash) const;
public: // config
bool _udp_only {false};
size_t _max_concurrent_in {32};
size_t _max_concurrent_out {16};
private:
mio::mmap_sink _file_map; // writable if not all
const FTInfoSHA1 _sha1_info;
const std::vector<uint8_t> _sha1_info_data;
const SHA1Digest _sha1_info_hash;
float _io_log_timer {0.f};
size_t _bytes_up {0};
size_t _bytes_up_last_log {0};
size_t _bytes_down {0};
size_t _bytes_down_last_log {0};
// index is the same as for info
std::vector<bool> _have_chunk;
bool _have_all {false};
@ -69,11 +84,7 @@ struct SHA1 final : public StateI {
// chunk_index -> time since request
std::map<size_t, float> _chunks_requested;
const size_t _max_concurrent_out {4};
const size_t _max_concurrent_in {16};
std::minstd_rand _rng {1337};
std::uniform_int_distribution<size_t> _distrib;
std::unordered_map<SHA1Digest, size_t> _chunk_hash_to_index;
@ -83,11 +94,27 @@ struct SHA1 final : public StateI {
std::vector<std::tuple<uint32_t, uint32_t, uint8_t, float>> _transfers_requested_info;
// group_number, peer_number, chunk_hash
std::deque<std::tuple<uint32_t, uint32_t, SHA1Digest>> _queue_requested_chunk;
std::deque<std::tuple<uint32_t, uint32_t, SHA1Digest, float>> _queue_requested_chunk;
// group_number, peer_number, transfer_id(i/o), seconds since (remote) activity, chunk index
std::vector<std::tuple<uint32_t, uint32_t, uint8_t, float, size_t>> _transfers_sending_chunk;
std::vector<std::tuple<uint32_t, uint32_t, uint8_t, float, size_t>> _transfers_receiving_chunk;
static constexpr size_t _peer_speed_mesurement_interval_count {20};
const float _peer_speed_mesurement_interval {0.5f}; // seconds
float _peer_speed_mesurement_interval_timer {0.f}; // seconds
// bytes received for last 6 intervals for peer
std::map<std::pair<uint32_t, uint32_t>, std::array<int64_t, _peer_speed_mesurement_interval_count>> _peer_in_bytes_array;
size_t _peer_in_bytes_array_index {0}; // current index into _peer_in_bytes_array. !ringbuffer!
// when chunk data is received, it is added to _peer_in_bytes_array_index in _peer_in_bytes_array
// every _peer_speed_mesurement_interval the avg is calculed and written to _peer_in_speed
// and the _peer_in_bytes_array_index is incremented by 1
std::map<std::pair<uint32_t, uint32_t>, float> _peer_in_speed;
// speed might be not the actual speed, since wrong data is removed afterwards (on "completion")
// so it can get negative. this makes this more useful for peer selection, less for userfacing stats
// _peer_in_speed feeds directly into _peer_in_targets_dist
std::vector<std::pair<uint32_t, uint32_t>> _peer_in_targets;
std::discrete_distribution<size_t> _peer_in_targets_dist;
};
} // States

View File

@ -21,6 +21,11 @@ void self_connection_status_cb(Tox*, TOX_CONNECTION connection_status, void *use
void friend_request_cb(Tox*, const uint8_t *public_key, const uint8_t *message, size_t length, void *user_data) {
static_cast<ToxClient*>(user_data)->onToxFriendRequest(public_key, std::string_view{reinterpret_cast<const char*>(message), length});
}
void group_peer_name_cb(Tox*, uint32_t group_number, uint32_t peer_id, const uint8_t* name, size_t length, void *user_data) {
static_cast<ToxClient*>(user_data)->onToxGroupPeerName(group_number, peer_id, std::string_view{reinterpret_cast<const char*>(name), length});
}
void group_custom_packet_cb(Tox*, uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length, void *user_data) {
static_cast<ToxClient*>(user_data)->onToxGroupCustomPacket(group_number, peer_id, data, length);
}

View File

@ -2,6 +2,8 @@
#include <tox/tox.h>
extern "C" {
// logging
void log_cb(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, const char *message, void *user_data);
@ -19,7 +21,7 @@ void friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *messa
//static void friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, void *user_data);
// ngc
//static void group_peer_name_cb(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t length, void *user_data);
void group_peer_name_cb(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *name, size_t length, void *user_data);
//static void group_peer_status_cb(Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_User_Status status, void *user_data);
//static void group_topic_cb(Tox *tox, uint32_t group_number, uint32_t peer_id, const uint8_t *topic, size_t length, void *user_data);
//static void group_privacy_state_cb(Tox *tox, uint32_t group_number, Tox_Group_Privacy_State privacy_state, void *user_data);
@ -52,3 +54,5 @@ bool ft1_recv_init_sha1_chunk_cb(Tox *tox, uint32_t group_number, uint32_t peer_
void ft1_recv_data_sha1_chunk_cb(Tox *tox, uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, size_t data_offset, const uint8_t* data, size_t data_size, void* user_data);
void ft1_send_data_sha1_chunk_cb(Tox *tox, uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, size_t data_offset, uint8_t* data, size_t data_size, void* user_data);
} // extern C

View File

@ -5,7 +5,6 @@
#include "./states/send_start_sha1.hpp"
#include "./states/receive_start_sha1.hpp"
#include "ngc_ft1.h"
#include <memory>
#include <sodium.h>
@ -26,9 +25,22 @@ ToxClient::ToxClient(const CommandLine& cl) :
// use cl for options
tox_options_set_log_callback(options, log_cb);
tox_options_set_local_discovery_enabled(options, false);
tox_options_set_udp_enabled(options, true);
tox_options_set_hole_punching_enabled(options, true);
tox_options_set_local_discovery_enabled(options, !cl.tox_disable_local_discovery);
tox_options_set_udp_enabled(options, !cl.tox_disable_udp);
tox_options_set_hole_punching_enabled(options, !cl.tox_disable_udp);
if (!cl.proxy_host.empty()) {
tox_options_set_proxy_host(options, cl.proxy_host.c_str());
tox_options_set_proxy_port(options, cl.proxy_port);
tox_options_set_proxy_type(options, Tox_Proxy_Type::TOX_PROXY_TYPE_SOCKS5);
} else {
tox_options_set_proxy_type(options, Tox_Proxy_Type::TOX_PROXY_TYPE_NONE);
}
if (cl.tox_port != 0) {
tox_options_set_start_port(options, cl.tox_port);
// TODO: extra end port?
tox_options_set_end_port(options, cl.tox_port);
}
std::vector<uint8_t> profile_data{};
if (!_tox_profile_path.empty()) {
@ -93,6 +105,7 @@ ToxClient::ToxClient(const CommandLine& cl) :
//CALLBACK_REG(friend_lossy_packet);
//CALLBACK_REG(friend_lossless_packet);
TOX_CALLBACK_REG(group_peer_name);
TOX_CALLBACK_REG(group_custom_packet);
TOX_CALLBACK_REG(group_custom_private_packet);
TOX_CALLBACK_REG(group_invite);
@ -109,6 +122,9 @@ ToxClient::ToxClient(const CommandLine& cl) :
_ext_ctx = NGC_EXT_new();
NGC_FT1_options ft1_options {};
ft1_options.acks_per_packet = cl.ft_acks_per_packet;
ft1_options.init_retry_timeout_after = cl.ft_init_retry_timeout_after;
ft1_options.sending_give_up_after = cl.ft_sending_give_up_after;
_ft1_ctx = NGC_FT1_new(&ft1_options);
NGC_FT1_register_ext(_ft1_ctx, _ext_ctx);
@ -163,6 +179,12 @@ ToxClient::ToxClient(const CommandLine& cl) :
}
}
if (!cl.chat_id.empty()) {
// TODO: move conversion and size check to cl
_join_group_after_dht_connect = hex2bin(cl.chat_id);
assert(_join_group_after_dht_connect.size() == TOX_GROUP_CHAT_ID_SIZE);
}
_tox_profile_dirty = true;
}
@ -174,11 +196,14 @@ ToxClient::~ToxClient(void) {
}
bool ToxClient::iterate(void) {
tox_iterate(_tox, this);
NGC_FT1_iterate(_tox, _ft1_ctx);
auto new_time = std::chrono::high_resolution_clock::now();
const float time_delta {std::chrono::duration<float>(new_time - _last_time).count()};
_last_time = new_time;
// HACK: hardcoded 5ms sleep in main
if (_state->iterate(0.005f)) {
tox_iterate(_tox, this);
NGC_FT1_iterate(_tox, _ft1_ctx, time_delta);
if (_state->iterate(time_delta)) {
_state = _state->nextState();
if (!_state) {
@ -187,6 +212,25 @@ bool ToxClient::iterate(void) {
}
}
_rejoin_group_timer -= time_delta;
if (_rejoin_group_timer <= 0.f) {
_rejoin_group_timer = 6.f * 60.f;
forEachGroup([this](const uint32_t group_number) {
// is connected or trying to connect
if (!tox_group_is_connected(_tox, group_number, nullptr)) {
std::cerr << "TCL disconnected group " << group_number << "\n";
return;
}
// never seen another peer
if (_groups.at(group_number).empty()) {
tox_group_reconnect(_tox, group_number, nullptr);
std::cerr << "TCL reconnecting empty group " << group_number << "\n";
}
});
}
if (_tox_profile_dirty) {
saveToxProfile();
}
@ -203,6 +247,18 @@ std::string ToxClient::getOwnAddress(void) const {
return bin2hex(self_addr);
}
std::string_view ToxClient::getGroupPeerName(uint32_t group_number, uint32_t peer_number) const {
if (_groups.count(group_number) && _groups.at(group_number).count(peer_number)) {
return _groups.at(group_number).at(peer_number).name;
} else {
return {""};
}
}
TOX_CONNECTION ToxClient::getGroupPeerConnectionStatus(uint32_t group_number, uint32_t peer_number) const {
return tox_group_peer_get_connection_status(_tox, group_number, peer_number, nullptr);
}
void ToxClient::onToxSelfConnectionStatus(TOX_CONNECTION connection_status) {
std::cout << "TCL self status: ";
switch (connection_status) {
@ -210,6 +266,25 @@ void ToxClient::onToxSelfConnectionStatus(TOX_CONNECTION connection_status) {
case TOX_CONNECTION::TOX_CONNECTION_TCP: std::cout << "TCP-relayed\n"; break;
case TOX_CONNECTION::TOX_CONNECTION_UDP: std::cout << "UDP-direct\n"; break;
}
if (connection_status != TOX_CONNECTION::TOX_CONNECTION_NONE && !_join_group_after_dht_connect.empty()) {
Tox_Err_Group_Join err;
uint32_t new_group_number = tox_group_join(
_tox,
_join_group_after_dht_connect.data(),
reinterpret_cast<const uint8_t*>(_self_name.data()), _self_name.size(),
nullptr, 0,
&err
);
if (err == TOX_ERR_GROUP_JOIN_OK) {
std::cout << "TCL joining group " << bin2hex(_join_group_after_dht_connect) << "\n";
_groups[new_group_number] = {};
} else {
std::cerr << "TCL error joining group failed " << err << "\n";
}
_join_group_after_dht_connect.clear();
}
_tox_profile_dirty = true;
}
@ -221,6 +296,20 @@ void ToxClient::onToxFriendRequest(const uint8_t* public_key, std::string_view m
_tox_profile_dirty = true;
}
void ToxClient::onToxGroupPeerName(uint32_t group_number, uint32_t peer_id, std::string_view name) {
std::cout << "TCL peer " << group_number << ":" << peer_id << " is now known as " << name << "\n";
_groups[group_number][peer_id].name = name;
}
//void ToxClient::onToxGroupPeerConnection(uint32_t group_number, uint32_t peer_id, TOX_CONNECTION connection_status) {
//std::cout << "TCL peer " << group_number << ":" << peer_id << " status: ";
//switch (connection_status) {
//case TOX_CONNECTION::TOX_CONNECTION_NONE: std::cout << "offline\n"; break;
//case TOX_CONNECTION::TOX_CONNECTION_TCP: std::cout << "TCP-relayed\n"; break;
//case TOX_CONNECTION::TOX_CONNECTION_UDP: std::cout << "UDP-direct\n"; break;
//}
//}
void ToxClient::onToxGroupCustomPacket(uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length) {
// TODO: signal private?
NGC_EXT_handle_group_custom_packet(_tox, _ext_ctx, group_number, peer_id, data, length);
@ -240,20 +329,37 @@ void ToxClient::onToxGroupInvite(uint32_t friend_number, const uint8_t* invite_d
void ToxClient::onToxGroupPeerJoin(uint32_t group_number, uint32_t peer_id) {
std::cout << "TCL group peer join " << group_number << ":" << peer_id << "\n";
_groups[group_number].emplace(peer_id);
std::vector<uint8_t> tmp_name;
{
Tox_Err_Group_Peer_Query err;
size_t length = tox_group_peer_get_name_size(_tox, group_number, peer_id, &err);
if (err == Tox_Err_Group_Peer_Query::TOX_ERR_GROUP_PEER_QUERY_OK) {
tmp_name.resize(length, '\0');
tox_group_peer_get_name(_tox, group_number, peer_id, tmp_name.data(), nullptr);
}
}
tmp_name.push_back('\0'); // make sure its null terminated
_groups[group_number][peer_id] = {
//tox_group_peer_get_connection_status(_tox, group_number, peer_id, nullptr),
reinterpret_cast<const char*>(tmp_name.data())
};
_tox_profile_dirty = true;
}
void ToxClient::onToxGroupPeerExit(uint32_t group_number, uint32_t peer_id, Tox_Group_Exit_Type exit_type, std::string_view name, std::string_view part_message) {
std::cout << "TCL group peer exit " << group_number << ":" << peer_id << "\n";
std::cout << "TCL group peer exit " << group_number << ":" << peer_id << " " << name << "\n";
_groups[group_number].erase(peer_id);
_tox_profile_dirty = true;
}
void ToxClient::onToxGroupSelfJoin(uint32_t group_number) {
std::cout << "TCL group self join " << group_number << "\n";
tox_group_self_set_name(_tox, group_number, reinterpret_cast<const uint8_t*>(_self_name.data()), _self_name.size(), nullptr);
// ???
// can be triggered after other peers allready joined o.o
// can be triggered after other peers already joined o.o
_tox_profile_dirty = true;
}
@ -263,7 +369,7 @@ StateI& ToxClient::getState(void) {
return *_state.get();
}
bool ToxClient::sendFT1RequestPrivate(uint32_t group_number, uint32_t peer_number, NGC_FT1_file_kind file_kind, const uint8_t* file_id, size_t file_id_size) {
bool ToxClient::sendFT1RequestPrivate(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size) {
NGC_FT1_send_request_private(
_tox, _ft1_ctx,
group_number, peer_number,
@ -275,7 +381,7 @@ bool ToxClient::sendFT1RequestPrivate(uint32_t group_number, uint32_t peer_numbe
return true;
}
bool ToxClient::sendFT1InitPrivate(uint32_t group_number, uint32_t peer_number, NGC_FT1_file_kind file_kind, const uint8_t* file_id, size_t file_id_size, uint64_t file_size, uint8_t& transfer_id) {
bool ToxClient::sendFT1InitPrivate(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size, uint64_t file_size, uint8_t& transfer_id) {
return NGC_FT1_send_init_private(
_tox, _ft1_ctx,
group_number, peer_number,

View File

@ -4,15 +4,17 @@
#include "./state.hpp"
#include <memory>
#include <tox/tox.h>
#include <ngc_ext.h>
#include <ngc_ft1.h>
#include <chrono>
#include <string>
#include <string_view>
#include <map>
#include <memory>
#include <set>
#include <vector>
// fwd
namespace States {
@ -31,6 +33,9 @@ struct ToxClient {
std::string getOwnAddress(void) const;
std::string_view getGroupPeerName(uint32_t group_number, uint32_t peer_number) const;
TOX_CONNECTION getGroupPeerConnectionStatus(uint32_t group_number, uint32_t peer_number) const;
template<typename FN>
void forEachGroup(FN&& fn) const {
for (const auto& it : _groups) {
@ -41,7 +46,7 @@ struct ToxClient {
template<typename FN>
void forEachGroupPeer(uint32_t group_number, FN&& fn) const {
if (_groups.count(group_number)) {
for (const uint32_t peer_number : _groups.at(group_number)) {
for (const auto& [peer_number, peer] : _groups.at(group_number)) {
fn(peer_number);
}
}
@ -50,6 +55,8 @@ struct ToxClient {
public: // tox callbacks
void onToxSelfConnectionStatus(TOX_CONNECTION connection_status);
void onToxFriendRequest(const uint8_t* public_key, std::string_view message);
void onToxGroupPeerName(uint32_t group_number, uint32_t peer_id, std::string_view name);
//void onToxGroupPeerConnection(uint32_t group_number, uint32_t peer_id, TOX_CONNECTION connection_status);
void onToxGroupCustomPacket(uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length);
void onToxGroupCustomPrivatePacket(uint32_t group_number, uint32_t peer_id, const uint8_t *data, size_t length);
void onToxGroupInvite(uint32_t friend_number, const uint8_t* invite_data, size_t invite_length, std::string_view group_name);
@ -61,8 +68,8 @@ struct ToxClient {
StateI& getState(void); // public accessor for callbacks
public: // FT1 sends
bool sendFT1RequestPrivate(uint32_t group_number, uint32_t peer_number, NGC_FT1_file_kind file_kind, const uint8_t* file_id, size_t file_id_size);
bool sendFT1InitPrivate(uint32_t group_number, uint32_t peer_number, NGC_FT1_file_kind file_kind, const uint8_t* file_id, size_t file_id_size, uint64_t file_size, uint8_t& transfer_id);
bool sendFT1RequestPrivate(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size);
bool sendFT1InitPrivate(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size, uint64_t file_size, uint8_t& transfer_id);
private:
void saveToxProfile(void);
@ -72,14 +79,22 @@ struct ToxClient {
NGC_EXT_CTX* _ext_ctx {nullptr};
NGC_FT1* _ft1_ctx {nullptr};
std::chrono::time_point<std::chrono::high_resolution_clock> _last_time {std::chrono::high_resolution_clock::now()};
std::string _self_name;
std::string _tox_profile_path;
bool _tox_profile_dirty {false}; // set in callbacks
std::vector<uint8_t> _join_group_after_dht_connect;
float _rejoin_group_timer {4.f * 60.f};
std::unique_ptr<StateI> _state;
// key groupid, value set of peer ids
std::map<uint32_t, std::set<uint32_t>> _groups;
struct Peer {
std::string name;
};
// key groupid, key peerid
std::map<uint32_t, std::map<uint32_t, Peer>> _groups;
};