Compare commits
1 Commits
eaaf798661
...
broken_som
Author | SHA1 | Date | |
---|---|---|---|
ae3dc74933 |
22
.gitignore
vendored
22
.gitignore
vendored
@ -1,22 +0,0 @@
|
|||||||
.vs/
|
|
||||||
*.o
|
|
||||||
*.swp
|
|
||||||
~*
|
|
||||||
*~
|
|
||||||
.idea/
|
|
||||||
cmake-build-debug/
|
|
||||||
cmake-build-debugandtest/
|
|
||||||
cmake-build-release/
|
|
||||||
*.stackdump
|
|
||||||
*.coredump
|
|
||||||
compile_commands.json
|
|
||||||
/build*
|
|
||||||
.clangd
|
|
||||||
.cache
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
.AppleDouble
|
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
CMakeLists.txt.user*
|
|
||||||
CMakeCache.txt
|
|
@ -51,23 +51,9 @@ add_library(solanaceae_sha1_ngcft1
|
|||||||
./solanaceae/ngc_ft1_sha1/hash_utils.hpp
|
./solanaceae/ngc_ft1_sha1/hash_utils.hpp
|
||||||
./solanaceae/ngc_ft1_sha1/hash_utils.cpp
|
./solanaceae/ngc_ft1_sha1/hash_utils.cpp
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/util.hpp
|
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/ft1_sha1_info.hpp
|
./solanaceae/ngc_ft1_sha1/ft1_sha1_info.hpp
|
||||||
./solanaceae/ngc_ft1_sha1/ft1_sha1_info.cpp
|
./solanaceae/ngc_ft1_sha1/ft1_sha1_info.cpp
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/components.hpp
|
|
||||||
./solanaceae/ngc_ft1_sha1/components.cpp
|
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/chunk_picker.hpp
|
|
||||||
./solanaceae/ngc_ft1_sha1/chunk_picker.cpp
|
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/participation.hpp
|
|
||||||
./solanaceae/ngc_ft1_sha1/participation.cpp
|
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/receiving_transfers.hpp
|
|
||||||
./solanaceae/ngc_ft1_sha1/receiving_transfers.cpp
|
|
||||||
|
|
||||||
./solanaceae/ngc_ft1_sha1/sha1_ngcft1.hpp
|
./solanaceae/ngc_ft1_sha1/sha1_ngcft1.hpp
|
||||||
./solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp
|
./solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp
|
||||||
)
|
)
|
||||||
@ -83,22 +69,3 @@ target_link_libraries(solanaceae_sha1_ngcft1 PUBLIC
|
|||||||
solanaceae_file2
|
solanaceae_file2
|
||||||
)
|
)
|
||||||
|
|
||||||
########################################
|
|
||||||
|
|
||||||
option(SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING "Build the solanaceae_ngcft1_sha1 tests" OFF)
|
|
||||||
message("II SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING " ${SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING})
|
|
||||||
|
|
||||||
# TODO: proper options n shit
|
|
||||||
if (SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING)
|
|
||||||
include(CTest)
|
|
||||||
|
|
||||||
#add_executable(bitset_tests
|
|
||||||
# ./solanaceae/ngc_ft1_sha1/bitset_tests.cpp
|
|
||||||
#)
|
|
||||||
|
|
||||||
#target_link_libraries(bitset_tests PUBLIC
|
|
||||||
# solanaceae_sha1_ngcft1
|
|
||||||
#)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
#include "./ngcext.hpp"
|
#include "./ngcext.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
NGCEXTEventProvider::NGCEXTEventProvider(ToxI& t, ToxEventProviderI& tep) : _t(t), _tep(tep) {
|
NGCEXTEventProvider::NGCEXTEventProvider(ToxEventProviderI& tep) : _tep(tep) {
|
||||||
_tep.subscribe(this, Tox_Event_Type::TOX_EVENT_GROUP_CUSTOM_PACKET);
|
_tep.subscribe(this, Tox_Event_Type::TOX_EVENT_GROUP_CUSTOM_PACKET);
|
||||||
_tep.subscribe(this, Tox_Event_Type::TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET);
|
_tep.subscribe(this, Tox_Event_Type::TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET);
|
||||||
}
|
}
|
||||||
@ -262,132 +261,6 @@ bool NGCEXTEventProvider::parse_ft1_init_ack_v2(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NGCEXTEventProvider::parse_ft1_have(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
) {
|
|
||||||
if (!_private) {
|
|
||||||
std::cerr << "NGCEXT: ft1_have cant be public\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Events::NGCEXT_ft1_have e;
|
|
||||||
e.group_number = group_number;
|
|
||||||
e.peer_number = peer_number;
|
|
||||||
size_t curser = 0;
|
|
||||||
|
|
||||||
// - 4 byte (file_kind)
|
|
||||||
e.file_kind = 0u;
|
|
||||||
_DATA_HAVE(sizeof(e.file_kind), std::cerr << "NGCEXT: packet too small, missing file_kind\n"; return false)
|
|
||||||
for (size_t i = 0; i < sizeof(e.file_kind); i++, curser++) {
|
|
||||||
e.file_kind |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
uint16_t file_id_size = 0u;
|
|
||||||
_DATA_HAVE(sizeof(file_id_size), std::cerr << "NGCEXT: packet too small, missing file_id_size\n"; return false)
|
|
||||||
for (size_t i = 0; i < sizeof(file_id_size); i++, curser++) {
|
|
||||||
file_id_size |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
|
|
||||||
_DATA_HAVE(file_id_size, std::cerr << "NGCEXT: packet too small, missing file_id, or file_id_size too large\n"; return false)
|
|
||||||
|
|
||||||
e.file_id = {data+curser, data+curser+file_id_size};
|
|
||||||
curser += file_id_size;
|
|
||||||
|
|
||||||
// - array [
|
|
||||||
// - 4 bytes (chunk index)
|
|
||||||
// - ]
|
|
||||||
while (curser < data_size) {
|
|
||||||
_DATA_HAVE(sizeof(uint32_t), std::cerr << "NGCEXT: packet too small, broken chunk index\n"; return false)
|
|
||||||
uint32_t chunk_index = 0u;
|
|
||||||
for (size_t i = 0; i < sizeof(chunk_index); i++, curser++) {
|
|
||||||
chunk_index |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
e.chunks.push_back(chunk_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dispatch(
|
|
||||||
NGCEXT_Event::FT1_HAVE,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::parse_ft1_bitset(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
) {
|
|
||||||
if (!_private) {
|
|
||||||
std::cerr << "NGCEXT: ft1_bitset cant be public\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Events::NGCEXT_ft1_bitset e;
|
|
||||||
e.group_number = group_number;
|
|
||||||
e.peer_number = peer_number;
|
|
||||||
size_t curser = 0;
|
|
||||||
|
|
||||||
// - 4 byte (file_kind)
|
|
||||||
e.file_kind = 0u;
|
|
||||||
_DATA_HAVE(sizeof(e.file_kind), std::cerr << "NGCEXT: packet too small, missing file_kind\n"; return false)
|
|
||||||
for (size_t i = 0; i < sizeof(e.file_kind); i++, curser++) {
|
|
||||||
e.file_kind |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
uint16_t file_id_size = 0u;
|
|
||||||
_DATA_HAVE(sizeof(file_id_size), std::cerr << "NGCEXT: packet too small, missing file_id_size\n"; return false)
|
|
||||||
for (size_t i = 0; i < sizeof(file_id_size); i++, curser++) {
|
|
||||||
file_id_size |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
|
|
||||||
_DATA_HAVE(file_id_size, std::cerr << "NGCEXT: packet too small, missing file_id, or file_id_size too large\n"; return false)
|
|
||||||
|
|
||||||
e.file_id = {data+curser, data+curser+file_id_size};
|
|
||||||
curser += file_id_size;
|
|
||||||
|
|
||||||
e.start_chunk = 0u;
|
|
||||||
_DATA_HAVE(sizeof(e.start_chunk), std::cerr << "NGCEXT: packet too small, missing start_chunk\n"; return false)
|
|
||||||
for (size_t i = 0; i < sizeof(e.start_chunk); i++, curser++) {
|
|
||||||
e.start_chunk |= uint32_t(data[curser]) << (i*8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - X bytes
|
|
||||||
// - array [
|
|
||||||
// - 1 bit (have chunk)
|
|
||||||
// - ] (filled up with zero)
|
|
||||||
// high to low?
|
|
||||||
// simply rest of file packet
|
|
||||||
e.chunk_bitset = {data+curser, data+curser+(data_size-curser)};
|
|
||||||
|
|
||||||
return dispatch(
|
|
||||||
NGCEXT_Event::FT1_BITSET,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::parse_pc1_announce(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
) {
|
|
||||||
// can be public
|
|
||||||
Events::NGCEXT_pc1_announce e;
|
|
||||||
e.group_number = group_number;
|
|
||||||
e.peer_number = peer_number;
|
|
||||||
size_t curser = 0;
|
|
||||||
|
|
||||||
// - X bytes (id, differnt sizes)
|
|
||||||
e.id = {data+curser, data+curser+(data_size-curser)};
|
|
||||||
|
|
||||||
return dispatch(
|
|
||||||
NGCEXT_Event::PC1_ANNOUNCE,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::handlePacket(
|
bool NGCEXTEventProvider::handlePacket(
|
||||||
const uint32_t group_number,
|
const uint32_t group_number,
|
||||||
const uint32_t peer_number,
|
const uint32_t peer_number,
|
||||||
@ -419,12 +292,6 @@ bool NGCEXTEventProvider::handlePacket(
|
|||||||
return parse_ft1_data_ack(group_number, peer_number, data+1, data_size-1, _private);
|
return parse_ft1_data_ack(group_number, peer_number, data+1, data_size-1, _private);
|
||||||
case NGCEXT_Event::FT1_MESSAGE:
|
case NGCEXT_Event::FT1_MESSAGE:
|
||||||
return parse_ft1_message(group_number, peer_number, data+1, data_size-1, _private);
|
return parse_ft1_message(group_number, peer_number, data+1, data_size-1, _private);
|
||||||
case NGCEXT_Event::FT1_HAVE:
|
|
||||||
return parse_ft1_have(group_number, peer_number, data+1, data_size-1, _private);
|
|
||||||
case NGCEXT_Event::FT1_BITSET:
|
|
||||||
return parse_ft1_bitset(group_number, peer_number, data+1, data_size-1, _private);
|
|
||||||
case NGCEXT_Event::PC1_ANNOUNCE:
|
|
||||||
return parse_pc1_announce(group_number, peer_number, data+1, data_size-1, _private);
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -432,257 +299,6 @@ bool NGCEXTEventProvider::handlePacket(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_request(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
) {
|
|
||||||
// - 1 byte packet id
|
|
||||||
// - 4 byte file_kind
|
|
||||||
// - X bytes file_id
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_REQUEST));
|
|
||||||
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
|
||||||
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < file_id_size; i++) {
|
|
||||||
pkg.push_back(file_id[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_init(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
uint64_t file_size,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
) {
|
|
||||||
// - 1 byte packet id
|
|
||||||
// - 4 byte (file_kind)
|
|
||||||
// - 8 bytes (data size)
|
|
||||||
// - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts)
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_INIT));
|
|
||||||
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
|
||||||
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < sizeof(file_size); i++) {
|
|
||||||
pkg.push_back((file_size>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
pkg.push_back(transfer_id);
|
|
||||||
for (size_t i = 0; i < file_id_size; i++) {
|
|
||||||
pkg.push_back(file_id[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_init_ack(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id
|
|
||||||
) {
|
|
||||||
// - 1 byte packet id
|
|
||||||
// - 1 byte transfer_id
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_INIT_ACK));
|
|
||||||
pkg.push_back(transfer_id);
|
|
||||||
|
|
||||||
// - 2 bytes max_lossy_data_size
|
|
||||||
const uint16_t max_lossy_data_size = _t.toxGroupMaxCustomLossyPacketLength() - 4;
|
|
||||||
for (size_t i = 0; i < sizeof(uint16_t); i++) {
|
|
||||||
pkg.push_back((max_lossy_data_size>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_data(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
uint16_t sequence_id,
|
|
||||||
const uint8_t* data, size_t data_size
|
|
||||||
) {
|
|
||||||
assert(data_size > 0);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// check header_size+data_size <= max pkg size
|
|
||||||
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.reserve(2048); // saves a ton of allocations
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_DATA));
|
|
||||||
pkg.push_back(transfer_id);
|
|
||||||
pkg.push_back(sequence_id & 0xff);
|
|
||||||
pkg.push_back((sequence_id >> (1*8)) & 0xff);
|
|
||||||
|
|
||||||
// TODO: optimize
|
|
||||||
for (size_t i = 0; i < data_size; i++) {
|
|
||||||
pkg.push_back(data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossy
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, false, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_data_ack(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
const uint16_t* seq_ids, size_t seq_ids_size
|
|
||||||
) {
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.reserve(1+1+2*32); // 32acks in a single pkg should be unlikely
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_DATA_ACK));
|
|
||||||
pkg.push_back(transfer_id);
|
|
||||||
|
|
||||||
// TODO: optimize
|
|
||||||
for (size_t i = 0; i < seq_ids_size; i++) {
|
|
||||||
pkg.push_back(seq_ids[i] & 0xff);
|
|
||||||
pkg.push_back((seq_ids[i] >> (1*8)) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossy
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, false, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_all_ft1_message(
|
|
||||||
uint32_t group_number,
|
|
||||||
uint32_t message_id,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
) {
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_MESSAGE));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(message_id); i++) {
|
|
||||||
pkg.push_back((message_id>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
|
||||||
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < file_id_size; i++) {
|
|
||||||
pkg.push_back(file_id[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPacket(group_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_have(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size,
|
|
||||||
const uint32_t* chunks_data, size_t chunks_size
|
|
||||||
) {
|
|
||||||
// 16bit file id size
|
|
||||||
assert(file_id_size <= 0xffff);
|
|
||||||
if (file_id_size > 0xffff) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_HAVE));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
|
||||||
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// file id not last in packet, needs explicit size
|
|
||||||
const uint16_t file_id_size_cast = file_id_size;
|
|
||||||
for (size_t i = 0; i < sizeof(file_id_size_cast); i++) {
|
|
||||||
pkg.push_back((file_id_size_cast>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < file_id_size; i++) {
|
|
||||||
pkg.push_back(file_id[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rest is chunks
|
|
||||||
for (size_t c_i = 0; c_i < chunks_size; c_i++) {
|
|
||||||
for (size_t i = 0; i < sizeof(chunks_data[c_i]); i++) {
|
|
||||||
pkg.push_back((chunks_data[c_i]>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_ft1_bitset(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size,
|
|
||||||
uint32_t start_chunk,
|
|
||||||
const uint8_t* bitset_data, size_t bitset_size // size is bytes
|
|
||||||
) {
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_BITSET));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
|
||||||
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// file id not last in packet, needs explicit size
|
|
||||||
const uint16_t file_id_size_cast = file_id_size;
|
|
||||||
for (size_t i = 0; i < sizeof(file_id_size_cast); i++) {
|
|
||||||
pkg.push_back((file_id_size_cast>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < file_id_size; i++) {
|
|
||||||
pkg.push_back(file_id[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(start_chunk); i++) {
|
|
||||||
pkg.push_back((start_chunk>>(i*8)) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < bitset_size; i++) {
|
|
||||||
pkg.push_back(bitset_data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lossless
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<uint8_t> build_pc1_announce(const uint8_t* id_data, size_t id_size) {
|
|
||||||
// - 1 byte packet id
|
|
||||||
// - X bytes (id, differnt sizes)
|
|
||||||
|
|
||||||
std::vector<uint8_t> pkg;
|
|
||||||
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::PC1_ANNOUNCE));
|
|
||||||
for (size_t i = 0; i < id_size; i++) {
|
|
||||||
pkg.push_back(id_data[i]);
|
|
||||||
}
|
|
||||||
return pkg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_pc1_announce(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* id_data, size_t id_size
|
|
||||||
) {
|
|
||||||
auto pkg = build_pc1_announce(id_data, id_size);
|
|
||||||
|
|
||||||
std::cout << "NEEP: sending PC1_ANNOUNCE s:" << pkg.size() - sizeof(NGCEXT_Event::PC1_ANNOUNCE) << "\n";
|
|
||||||
|
|
||||||
// lossless?
|
|
||||||
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::send_all_pc1_announce(
|
|
||||||
uint32_t group_number,
|
|
||||||
const uint8_t* id_data, size_t id_size
|
|
||||||
) {
|
|
||||||
auto pkg = build_pc1_announce(id_data, id_size);
|
|
||||||
|
|
||||||
std::cout << "NEEP: sending all PC1_ANNOUNCE s:" << pkg.size() - sizeof(NGCEXT_Event::PC1_ANNOUNCE) << "\n";
|
|
||||||
|
|
||||||
// lossless?
|
|
||||||
return _t.toxGroupSendCustomPacket(group_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NGCEXTEventProvider::onToxEvent(const Tox_Event_Group_Custom_Packet* e) {
|
bool NGCEXTEventProvider::onToxEvent(const Tox_Event_Group_Custom_Packet* e) {
|
||||||
const auto group_number = tox_event_group_custom_packet_get_group_number(e);
|
const auto group_number = tox_event_group_custom_packet_get_group_number(e);
|
||||||
const auto peer_number = tox_event_group_custom_packet_get_peer_id(e);
|
const auto peer_number = tox_event_group_custom_packet_get_peer_id(e);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// solanaceae port of tox_ngc_ext
|
// solanaceae port of tox_ngc_ext
|
||||||
|
|
||||||
#include <solanaceae/toxcore/tox_event_interface.hpp>
|
#include <solanaceae/toxcore/tox_event_interface.hpp>
|
||||||
#include <solanaceae/toxcore/tox_interface.hpp>
|
|
||||||
#include <solanaceae/util/event_provider.hpp>
|
#include <solanaceae/util/event_provider.hpp>
|
||||||
|
|
||||||
#include <solanaceae/toxcore/tox_key.hpp>
|
#include <solanaceae/toxcore/tox_key.hpp>
|
||||||
@ -120,6 +119,7 @@ namespace Events {
|
|||||||
// - 4 byte (message_id)
|
// - 4 byte (message_id)
|
||||||
uint32_t message_id;
|
uint32_t message_id;
|
||||||
|
|
||||||
|
// request the other side to initiate a FT
|
||||||
// - 4 byte (file_kind)
|
// - 4 byte (file_kind)
|
||||||
uint32_t file_kind;
|
uint32_t file_kind;
|
||||||
|
|
||||||
@ -127,49 +127,6 @@ namespace Events {
|
|||||||
std::vector<uint8_t> file_id;
|
std::vector<uint8_t> file_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NGCEXT_ft1_have {
|
|
||||||
uint32_t group_number;
|
|
||||||
uint32_t peer_number;
|
|
||||||
|
|
||||||
// - 4 byte (file_kind)
|
|
||||||
uint32_t file_kind;
|
|
||||||
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
std::vector<uint8_t> file_id;
|
|
||||||
|
|
||||||
// - array [
|
|
||||||
// - 4 bytes (chunk index)
|
|
||||||
// - ]
|
|
||||||
std::vector<uint32_t> chunks;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NGCEXT_ft1_bitset {
|
|
||||||
uint32_t group_number;
|
|
||||||
uint32_t peer_number;
|
|
||||||
|
|
||||||
// - 4 byte (file_kind)
|
|
||||||
uint32_t file_kind;
|
|
||||||
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
std::vector<uint8_t> file_id;
|
|
||||||
|
|
||||||
uint32_t start_chunk;
|
|
||||||
|
|
||||||
// - array [
|
|
||||||
// - 1 bit (have chunk)
|
|
||||||
// - ] (filled up with zero)
|
|
||||||
// high to low?
|
|
||||||
std::vector<uint8_t> chunk_bitset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NGCEXT_pc1_announce {
|
|
||||||
uint32_t group_number;
|
|
||||||
uint32_t peer_number;
|
|
||||||
|
|
||||||
// - X bytes (id, differnt sizes)
|
|
||||||
std::vector<uint8_t> id;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Events
|
} // Events
|
||||||
|
|
||||||
enum class NGCEXT_Event : uint8_t {
|
enum class NGCEXT_Event : uint8_t {
|
||||||
@ -229,44 +186,11 @@ enum class NGCEXT_Event : uint8_t {
|
|||||||
// send file as message
|
// send file as message
|
||||||
// basically the opposite of request
|
// basically the opposite of request
|
||||||
// contains file_kind and file_id (and timestamp?)
|
// contains file_kind and file_id (and timestamp?)
|
||||||
// - 4 bytes (message_id)
|
// - 4 byte (message_id)
|
||||||
// - 4 bytes (file_kind)
|
// - 4 byte (file_kind)
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
// - X bytes (file_kind dependent id, differnt sizes)
|
||||||
FT1_MESSAGE,
|
FT1_MESSAGE,
|
||||||
|
|
||||||
// announce you have specified chunks, for given info
|
|
||||||
// this is info/chunk specific
|
|
||||||
// bundle these together to reduce overhead (like maybe every 16, max 1min)
|
|
||||||
// - 4 bytes (file_kind)
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
// - array [
|
|
||||||
// - 4 bytes (chunk index)
|
|
||||||
// - ]
|
|
||||||
FT1_HAVE,
|
|
||||||
|
|
||||||
// tell the other peer which chunks, for a given info you have
|
|
||||||
// compressed down to a bitset (in parts)
|
|
||||||
// supposed to only be sent once on participation announcement, when mutual interest
|
|
||||||
// it is always assumed by the other side, that you dont have the chunk, until told otherwise,
|
|
||||||
// so you can be smart about what you send.
|
|
||||||
// - 4 bytes (file_kind)
|
|
||||||
// - X bytes (file_kind dependent id, differnt sizes)
|
|
||||||
// - 4 bytes (first chunk index in bitset)
|
|
||||||
// - array [
|
|
||||||
// - 1 bit (have chunk)
|
|
||||||
// - ] (filled up with zero)
|
|
||||||
FT1_BITSET,
|
|
||||||
|
|
||||||
// TODO: FT1_IDONTHAVE, tell a peer you no longer have said chunk
|
|
||||||
// TODO: FT1_REJECT, tell a peer you wont fulfil the request
|
|
||||||
|
|
||||||
// tell another peer that you are participating in X
|
|
||||||
// you can reply with PC1_ANNOUNCE, to let the other side know, you too are participating in X
|
|
||||||
// you should NOT announce often, since this hits peers that not participate
|
|
||||||
// ft1 uses fk+id
|
|
||||||
// - x bytes (id, different sizes)
|
|
||||||
PC1_ANNOUNCE = 0x80 | 32u,
|
|
||||||
|
|
||||||
MAX
|
MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -280,19 +204,15 @@ struct NGCEXTEventI {
|
|||||||
virtual bool onEvent(const Events::NGCEXT_ft1_data&) { return false; }
|
virtual bool onEvent(const Events::NGCEXT_ft1_data&) { return false; }
|
||||||
virtual bool onEvent(const Events::NGCEXT_ft1_data_ack&) { return false; }
|
virtual bool onEvent(const Events::NGCEXT_ft1_data_ack&) { return false; }
|
||||||
virtual bool onEvent(const Events::NGCEXT_ft1_message&) { return false; }
|
virtual bool onEvent(const Events::NGCEXT_ft1_message&) { return false; }
|
||||||
virtual bool onEvent(const Events::NGCEXT_ft1_have&) { return false; }
|
|
||||||
virtual bool onEvent(const Events::NGCEXT_ft1_bitset&) { return false; }
|
|
||||||
virtual bool onEvent(const Events::NGCEXT_pc1_announce&) { return false; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using NGCEXTEventProviderI = EventProviderI<NGCEXTEventI>;
|
using NGCEXTEventProviderI = EventProviderI<NGCEXTEventI>;
|
||||||
|
|
||||||
class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI {
|
class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI {
|
||||||
ToxI& _t;
|
|
||||||
ToxEventProviderI& _tep;
|
ToxEventProviderI& _tep;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NGCEXTEventProvider(ToxI& t, ToxEventProviderI& tep);
|
NGCEXTEventProvider(ToxEventProviderI& tep/*, ToxI& t*/);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool parse_hs1_request_last_ids(
|
bool parse_hs1_request_last_ids(
|
||||||
@ -349,24 +269,6 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI {
|
|||||||
bool _private
|
bool _private
|
||||||
);
|
);
|
||||||
|
|
||||||
bool parse_ft1_have(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
);
|
|
||||||
|
|
||||||
bool parse_ft1_bitset(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
);
|
|
||||||
|
|
||||||
bool parse_pc1_announce(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* data, size_t data_size,
|
|
||||||
bool _private
|
|
||||||
);
|
|
||||||
|
|
||||||
bool handlePacket(
|
bool handlePacket(
|
||||||
const uint32_t group_number,
|
const uint32_t group_number,
|
||||||
const uint32_t peer_number,
|
const uint32_t peer_number,
|
||||||
@ -375,72 +277,6 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI {
|
|||||||
const bool _private
|
const bool _private
|
||||||
);
|
);
|
||||||
|
|
||||||
public: // send api
|
|
||||||
bool send_ft1_request(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_init(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
uint64_t file_size,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_init_ack(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_data(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
uint16_t sequence_id,
|
|
||||||
const uint8_t* data, size_t data_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_data_ack(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint8_t transfer_id,
|
|
||||||
const uint16_t* seq_ids, size_t seq_ids_size
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: add private version
|
|
||||||
bool send_all_ft1_message(
|
|
||||||
uint32_t group_number,
|
|
||||||
uint32_t message_id,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_have(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size,
|
|
||||||
const uint32_t* chunks_data, size_t chunks_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_ft1_bitset(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
uint32_t file_kind,
|
|
||||||
const uint8_t* file_id, size_t file_id_size,
|
|
||||||
uint32_t start_chunk,
|
|
||||||
const uint8_t* bitset_data, size_t bitset_size // size is bytes
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_pc1_announce(
|
|
||||||
uint32_t group_number, uint32_t peer_number,
|
|
||||||
const uint8_t* id_data, size_t id_size
|
|
||||||
);
|
|
||||||
|
|
||||||
bool send_all_pc1_announce(
|
|
||||||
uint32_t group_number,
|
|
||||||
const uint8_t* id_data, size_t id_size
|
|
||||||
);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onToxEvent(const Tox_Event_Group_Custom_Packet* e) override;
|
bool onToxEvent(const Tox_Event_Group_Custom_Packet* e) override;
|
||||||
bool onToxEvent(const Tox_Event_Group_Custom_Private_Packet* e) override;
|
bool onToxEvent(const Tox_Event_Group_Custom_Private_Packet* e) override;
|
||||||
|
@ -51,6 +51,7 @@ void CUBIC::onCongestion(void) {
|
|||||||
const auto current_cwnd = getCWnD(); // TODO: remove, only used by logging?
|
const auto current_cwnd = getCWnD(); // TODO: remove, only used by logging?
|
||||||
const auto current_wnd = getWindow(); // respects cwnd and fwnd
|
const auto current_wnd = getWindow(); // respects cwnd and fwnd
|
||||||
|
|
||||||
|
_bytes_leftover = 0;
|
||||||
resetReductionTimer();
|
resetReductionTimer();
|
||||||
|
|
||||||
if (current_cwnd < _window_max) {
|
if (current_cwnd < _window_max) {
|
||||||
@ -90,7 +91,7 @@ int64_t CUBIC::canSend(float time_delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto window = getCWnD();
|
const auto window = getCWnD();
|
||||||
int64_t cspace_bytes = window - _in_flight_bytes;
|
int64_t cspace_bytes = (window - _in_flight_bytes) + _bytes_leftover;
|
||||||
if (cspace_bytes < MAXIMUM_SEGMENT_DATA_SIZE) {
|
if (cspace_bytes < MAXIMUM_SEGMENT_DATA_SIZE) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
@ -106,6 +107,8 @@ int64_t CUBIC::canSend(float time_delta) {
|
|||||||
// limit to whole packets
|
// limit to whole packets
|
||||||
int64_t cspace_pkgs = (cspace_bytes / MAXIMUM_SEGMENT_DATA_SIZE) * MAXIMUM_SEGMENT_DATA_SIZE;
|
int64_t cspace_pkgs = (cspace_bytes / MAXIMUM_SEGMENT_DATA_SIZE) * MAXIMUM_SEGMENT_DATA_SIZE;
|
||||||
|
|
||||||
|
_bytes_leftover = cspace_bytes - cspace_pkgs;
|
||||||
|
|
||||||
return std::min(cspace_pkgs, fspace_pkgs);
|
return std::min(cspace_pkgs, fspace_pkgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ struct CUBIC : public FlowOnly {
|
|||||||
//double _window_last_max {2.f * MAXIMUM_SEGMENT_SIZE};
|
//double _window_last_max {2.f * MAXIMUM_SEGMENT_SIZE};
|
||||||
|
|
||||||
double _time_since_reduction {12.f}; // warm start
|
double _time_since_reduction {12.f}; // warm start
|
||||||
|
int64_t _bytes_leftover {0};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateReductionTimer(float time_delta);
|
void updateReductionTimer(float time_delta);
|
||||||
|
@ -15,6 +15,147 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_REQUEST(
|
||||||
|
uint32_t group_number, uint32_t peer_number,
|
||||||
|
uint32_t file_kind,
|
||||||
|
const uint8_t* file_id, size_t file_id_size
|
||||||
|
) {
|
||||||
|
// - 1 byte packet id
|
||||||
|
// - 4 byte file_kind
|
||||||
|
// - X bytes file_id
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_REQUEST));
|
||||||
|
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
||||||
|
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < file_id_size; i++) {
|
||||||
|
pkg.push_back(file_id[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossless
|
||||||
|
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_INIT(
|
||||||
|
uint32_t group_number, uint32_t peer_number,
|
||||||
|
uint32_t file_kind,
|
||||||
|
uint64_t file_size,
|
||||||
|
uint8_t transfer_id,
|
||||||
|
const uint8_t* file_id, size_t file_id_size
|
||||||
|
) {
|
||||||
|
// - 1 byte packet id
|
||||||
|
// - 4 byte (file_kind)
|
||||||
|
// - 8 bytes (data size)
|
||||||
|
// - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts)
|
||||||
|
// - X bytes (file_kind dependent id, differnt sizes)
|
||||||
|
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_INIT));
|
||||||
|
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
||||||
|
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < sizeof(file_size); i++) {
|
||||||
|
pkg.push_back((file_size>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
pkg.push_back(transfer_id);
|
||||||
|
for (size_t i = 0; i < file_id_size; i++) {
|
||||||
|
pkg.push_back(file_id[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossless
|
||||||
|
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_INIT_ACK(
|
||||||
|
uint32_t group_number, uint32_t peer_number,
|
||||||
|
uint8_t transfer_id
|
||||||
|
) {
|
||||||
|
// - 1 byte packet id
|
||||||
|
// - 1 byte transfer_id
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_INIT_ACK));
|
||||||
|
pkg.push_back(transfer_id);
|
||||||
|
|
||||||
|
// - 2 bytes max_lossy_data_size
|
||||||
|
const uint16_t max_lossy_data_size = _t.toxGroupMaxCustomLossyPacketLength() - 4;
|
||||||
|
for (size_t i = 0; i < sizeof(uint16_t); i++) {
|
||||||
|
pkg.push_back((max_lossy_data_size>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossless
|
||||||
|
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_DATA(
|
||||||
|
uint32_t group_number, uint32_t peer_number,
|
||||||
|
uint8_t transfer_id,
|
||||||
|
uint16_t sequence_id,
|
||||||
|
const uint8_t* data, size_t data_size
|
||||||
|
) {
|
||||||
|
assert(data_size > 0);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// check header_size+data_size <= max pkg size
|
||||||
|
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.reserve(2048); // saves a ton of allocations
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_DATA));
|
||||||
|
pkg.push_back(transfer_id);
|
||||||
|
pkg.push_back(sequence_id & 0xff);
|
||||||
|
pkg.push_back((sequence_id >> (1*8)) & 0xff);
|
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
for (size_t i = 0; i < data_size; i++) {
|
||||||
|
pkg.push_back(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossy
|
||||||
|
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, false, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_DATA_ACK(
|
||||||
|
uint32_t group_number, uint32_t peer_number,
|
||||||
|
uint8_t transfer_id,
|
||||||
|
const uint16_t* seq_ids, size_t seq_ids_size
|
||||||
|
) {
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.reserve(1+1+2*32); // 32acks in a single pkg should be unlikely
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_DATA_ACK));
|
||||||
|
pkg.push_back(transfer_id);
|
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
for (size_t i = 0; i < seq_ids_size; i++) {
|
||||||
|
pkg.push_back(seq_ids[i] & 0xff);
|
||||||
|
pkg.push_back((seq_ids[i] >> (1*8)) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossy
|
||||||
|
return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, false, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NGCFT1::sendPKG_FT1_MESSAGE(
|
||||||
|
uint32_t group_number,
|
||||||
|
uint32_t message_id,
|
||||||
|
uint32_t file_kind,
|
||||||
|
const uint8_t* file_id, size_t file_id_size
|
||||||
|
) {
|
||||||
|
std::vector<uint8_t> pkg;
|
||||||
|
pkg.push_back(static_cast<uint8_t>(NGCEXT_Event::FT1_MESSAGE));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(message_id); i++) {
|
||||||
|
pkg.push_back((message_id>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < sizeof(file_kind); i++) {
|
||||||
|
pkg.push_back((file_kind>>(i*8)) & 0xff);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < file_id_size; i++) {
|
||||||
|
pkg.push_back(file_id[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lossless
|
||||||
|
return _t.toxGroupSendCustomPacket(group_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer, size_t idx, std::set<CCAI::SeqIDType>& timeouts_set, int64_t& can_packet_size) {
|
void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer, size_t idx, std::set<CCAI::SeqIDType>& timeouts_set, int64_t& can_packet_size) {
|
||||||
auto& tf_opt = peer.send_transfers.at(idx);
|
auto& tf_opt = peer.send_transfers.at(idx);
|
||||||
assert(tf_opt.has_value());
|
assert(tf_opt.has_value());
|
||||||
@ -40,8 +181,7 @@ void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_
|
|||||||
} else {
|
} else {
|
||||||
// timed out, resend
|
// timed out, resend
|
||||||
std::cerr << "NGCFT1 warning: ft init timed out, resending\n";
|
std::cerr << "NGCFT1 warning: ft init timed out, resending\n";
|
||||||
//sendPKG_FT1_INIT(group_number, peer_number, tf.file_kind, tf.file_size, idx, tf.file_id.data(), tf.file_id.size());
|
sendPKG_FT1_INIT(group_number, peer_number, tf.file_kind, tf.file_size, idx, tf.file_id.data(), tf.file_id.size());
|
||||||
_neep.send_ft1_init(group_number, peer_number, tf.file_kind, tf.file_size, idx, tf.file_id.data(), tf.file_id.size());
|
|
||||||
tf.inits_sent++;
|
tf.inits_sent++;
|
||||||
tf.time_since_activity = 0.f;
|
tf.time_since_activity = 0.f;
|
||||||
}
|
}
|
||||||
@ -51,7 +191,7 @@ void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_
|
|||||||
case State::FINISHING: // we still have unacked packets
|
case State::FINISHING: // we still have unacked packets
|
||||||
tf.ssb.for_each(time_delta, [&](uint16_t id, const std::vector<uint8_t>& data, float& time_since_activity) {
|
tf.ssb.for_each(time_delta, [&](uint16_t id, const std::vector<uint8_t>& data, float& time_since_activity) {
|
||||||
if (can_packet_size >= data.size() && timeouts_set.count({idx, id})) {
|
if (can_packet_size >= data.size() && timeouts_set.count({idx, id})) {
|
||||||
_neep.send_ft1_data(group_number, peer_number, idx, id, data.data(), data.size());
|
sendPKG_FT1_DATA(group_number, peer_number, idx, id, data.data(), data.size());
|
||||||
peer.cca->onLoss({idx, id}, false);
|
peer.cca->onLoss({idx, id}, false);
|
||||||
time_since_activity = 0.f;
|
time_since_activity = 0.f;
|
||||||
timeouts_set.erase({idx, id});
|
timeouts_set.erase({idx, id});
|
||||||
@ -101,7 +241,7 @@ void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_
|
|||||||
tf.ssb.for_each(time_delta, [&](uint16_t id, const std::vector<uint8_t>& data, float& time_since_activity) {
|
tf.ssb.for_each(time_delta, [&](uint16_t id, const std::vector<uint8_t>& data, float& time_since_activity) {
|
||||||
if (can_packet_size >= data.size() && time_since_activity >= peer.cca->getCurrentDelay() && timeouts_set.count({idx, id})) {
|
if (can_packet_size >= data.size() && time_since_activity >= peer.cca->getCurrentDelay() && timeouts_set.count({idx, id})) {
|
||||||
// TODO: can fail
|
// TODO: can fail
|
||||||
_neep.send_ft1_data(group_number, peer_number, idx, id, data.data(), data.size());
|
sendPKG_FT1_DATA(group_number, peer_number, idx, id, data.data(), data.size());
|
||||||
peer.cca->onLoss({idx, id}, false);
|
peer.cca->onLoss({idx, id}, false);
|
||||||
time_since_activity = 0.f;
|
time_since_activity = 0.f;
|
||||||
timeouts_set.erase({idx, id});
|
timeouts_set.erase({idx, id});
|
||||||
@ -138,7 +278,7 @@ void NGCFT1::updateSendTransfer(float time_delta, uint32_t group_number, uint32_
|
|||||||
);
|
);
|
||||||
|
|
||||||
uint16_t seq_id = tf.ssb.add(std::move(new_data));
|
uint16_t seq_id = tf.ssb.add(std::move(new_data));
|
||||||
const bool sent = _neep.send_ft1_data(group_number, peer_number, idx, seq_id, tf.ssb.entries.at(seq_id).data.data(), tf.ssb.entries.at(seq_id).data.size());
|
const bool sent = sendPKG_FT1_DATA(group_number, peer_number, idx, seq_id, tf.ssb.entries.at(seq_id).data.data(), tf.ssb.entries.at(seq_id).data.size());
|
||||||
if (sent) {
|
if (sent) {
|
||||||
peer.cca->onSent({idx, seq_id}, chunk_size);
|
peer.cca->onSent({idx, seq_id}, chunk_size);
|
||||||
} else {
|
} else {
|
||||||
@ -198,7 +338,7 @@ void NGCFT1::iteratePeer(float time_delta, uint32_t group_number, uint32_t peer_
|
|||||||
NGCFT1::NGCFT1(
|
NGCFT1::NGCFT1(
|
||||||
ToxI& t,
|
ToxI& t,
|
||||||
ToxEventProviderI& tep,
|
ToxEventProviderI& tep,
|
||||||
NGCEXTEventProvider& neep
|
NGCEXTEventProviderI& neep
|
||||||
) : _t(t), _tep(tep), _neep(neep)
|
) : _t(t), _tep(tep), _neep(neep)
|
||||||
{
|
{
|
||||||
_neep.subscribe(this, NGCEXT_Event::FT1_REQUEST);
|
_neep.subscribe(this, NGCEXT_Event::FT1_REQUEST);
|
||||||
@ -252,7 +392,7 @@ void NGCFT1::NGC_FT1_send_request_private(
|
|||||||
const uint8_t* file_id, size_t file_id_size
|
const uint8_t* file_id, size_t file_id_size
|
||||||
) {
|
) {
|
||||||
// TODO: error check
|
// TODO: error check
|
||||||
_neep.send_ft1_request(group_number, peer_number, file_kind, file_id, file_id_size);
|
sendPKG_FT1_REQUEST(group_number, peer_number, file_kind, file_id, file_id_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NGCFT1::NGC_FT1_send_init_private(
|
bool NGCFT1::NGC_FT1_send_init_private(
|
||||||
@ -293,7 +433,7 @@ bool NGCFT1::NGC_FT1_send_init_private(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check return value
|
// TODO: check return value
|
||||||
_neep.send_ft1_init(group_number, peer_number, file_kind, file_size, idx, file_id, file_id_size);
|
sendPKG_FT1_INIT(group_number, peer_number, file_kind, file_size, idx, file_id, file_id_size);
|
||||||
|
|
||||||
peer.send_transfers[idx] = Group::Peer::SendTransfer{
|
peer.send_transfers[idx] = Group::Peer::SendTransfer{
|
||||||
file_kind,
|
file_kind,
|
||||||
@ -323,7 +463,7 @@ bool NGCFT1::NGC_FT1_send_message_public(
|
|||||||
message_id = randombytes_random();
|
message_id = randombytes_random();
|
||||||
|
|
||||||
// TODO: check return value
|
// TODO: check return value
|
||||||
return _neep.send_all_ft1_message(group_number, message_id, file_kind, file_id, file_id_size);
|
return sendPKG_FT1_MESSAGE(group_number, message_id, file_kind, file_id, file_id_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NGCFT1::onEvent(const Events::NGCEXT_ft1_request& e) {
|
bool NGCFT1::onEvent(const Events::NGCEXT_ft1_request& e) {
|
||||||
@ -366,13 +506,13 @@ bool NGCFT1::onEvent(const Events::NGCEXT_ft1_init& e) {
|
|||||||
return true; // return true?
|
return true; // return true?
|
||||||
}
|
}
|
||||||
|
|
||||||
_neep.send_ft1_init_ack(e.group_number, e.peer_number, e.transfer_id);
|
sendPKG_FT1_INIT_ACK(e.group_number, e.peer_number, e.transfer_id);
|
||||||
|
|
||||||
std::cout << "NGCFT1: accepted init\n";
|
std::cout << "NGCFT1: accepted init\n";
|
||||||
|
|
||||||
auto& peer = groups[e.group_number].peers[e.peer_number];
|
auto& peer = groups[e.group_number].peers[e.peer_number];
|
||||||
if (peer.recv_transfers[e.transfer_id].has_value()) {
|
if (peer.recv_transfers[e.transfer_id].has_value()) {
|
||||||
std::cerr << "NGCFT1 warning: overwriting existing recv_transfer " << int(e.transfer_id) << ", other peer started new transfer on preexising\n";
|
std::cerr << "NGCFT1 warning: overwriting existing recv_transfer " << int(e.transfer_id) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
peer.recv_transfers[e.transfer_id] = Group::Peer::RecvTransfer{
|
peer.recv_transfers[e.transfer_id] = Group::Peer::RecvTransfer{
|
||||||
@ -488,7 +628,7 @@ bool NGCFT1::onEvent(const Events::NGCEXT_ft1_data& e) {
|
|||||||
// TODO: check if this caps at max acks
|
// TODO: check if this caps at max acks
|
||||||
if (!ack_seq_ids.empty()) {
|
if (!ack_seq_ids.empty()) {
|
||||||
// TODO: check return value
|
// TODO: check return value
|
||||||
_neep.send_ft1_data_ack(e.group_number, e.peer_number, e.transfer_id, ack_seq_ids.data(), ack_seq_ids.size());
|
sendPKG_FT1_DATA_ACK(e.group_number, e.peer_number, e.transfer_id, ack_seq_ids.data(), ack_seq_ids.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -502,11 +642,6 @@ bool NGCFT1::onEvent(const Events::NGCEXT_ft1_data& e) {
|
|||||||
e.transfer_id
|
e.transfer_id
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// delete transfer
|
|
||||||
// TODO: keep around for remote timeout + delay + offset, so we can be sure all acks where received
|
|
||||||
// or implement a dedicated finished that needs to be acked
|
|
||||||
peer.recv_transfers[e.transfer_id].reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -131,7 +131,7 @@ using NGCFT1EventProviderI = EventProviderI<NGCFT1EventI>;
|
|||||||
class NGCFT1 : public ToxEventI, public NGCEXTEventI, public NGCFT1EventProviderI {
|
class NGCFT1 : public ToxEventI, public NGCEXTEventI, public NGCFT1EventProviderI {
|
||||||
ToxI& _t;
|
ToxI& _t;
|
||||||
ToxEventProviderI& _tep;
|
ToxEventProviderI& _tep;
|
||||||
NGCEXTEventProvider& _neep; // not the interface?
|
NGCEXTEventProviderI& _neep;
|
||||||
|
|
||||||
std::default_random_engine _rng{std::random_device{}()};
|
std::default_random_engine _rng{std::random_device{}()};
|
||||||
|
|
||||||
@ -201,6 +201,13 @@ class NGCFT1 : public ToxEventI, public NGCEXTEventI, public NGCFT1EventProvider
|
|||||||
std::map<uint32_t, Group> groups;
|
std::map<uint32_t, Group> groups;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool sendPKG_FT1_REQUEST(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size);
|
||||||
|
bool sendPKG_FT1_INIT(uint32_t group_number, uint32_t peer_number, uint32_t file_kind, uint64_t file_size, uint8_t transfer_id, const uint8_t* file_id, size_t file_id_size);
|
||||||
|
bool sendPKG_FT1_INIT_ACK(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id);
|
||||||
|
bool sendPKG_FT1_DATA(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, uint16_t sequence_id, const uint8_t* data, size_t data_size);
|
||||||
|
bool sendPKG_FT1_DATA_ACK(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, const uint16_t* seq_ids, size_t seq_ids_size);
|
||||||
|
bool sendPKG_FT1_MESSAGE(uint32_t group_number, uint32_t message_id, uint32_t file_kind, const uint8_t* file_id, size_t file_id_size);
|
||||||
|
|
||||||
void updateSendTransfer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer, size_t idx, std::set<CCAI::SeqIDType>& timeouts_set, int64_t& can_packet_size);
|
void updateSendTransfer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer, size_t idx, std::set<CCAI::SeqIDType>& timeouts_set, int64_t& can_packet_size);
|
||||||
void iteratePeer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer);
|
void iteratePeer(float time_delta, uint32_t group_number, uint32_t peer_number, Group::Peer& peer);
|
||||||
|
|
||||||
@ -208,7 +215,7 @@ class NGCFT1 : public ToxEventI, public NGCEXTEventI, public NGCFT1EventProvider
|
|||||||
NGCFT1(
|
NGCFT1(
|
||||||
ToxI& t,
|
ToxI& t,
|
||||||
ToxEventProviderI& tep,
|
ToxEventProviderI& tep,
|
||||||
NGCEXTEventProvider& neep
|
NGCEXTEventProviderI& neep
|
||||||
);
|
);
|
||||||
|
|
||||||
float iterate(float delta);
|
float iterate(float delta);
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
#include "./chunk_picker.hpp"
|
|
||||||
|
|
||||||
#include <solanaceae/tox_contacts/components.hpp>
|
|
||||||
|
|
||||||
#include "./components.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
void ChunkPicker::updateParticipation(
|
|
||||||
Contact3Handle c,
|
|
||||||
ObjectRegistry& objreg
|
|
||||||
) {
|
|
||||||
// replaces them in place
|
|
||||||
participating.clear();
|
|
||||||
participating_unfinished.clear();
|
|
||||||
|
|
||||||
for (const Object ov : objreg.view<Components::SuspectedParticipants>()) {
|
|
||||||
const ObjectHandle o {objreg, ov};
|
|
||||||
|
|
||||||
participating.emplace(o);
|
|
||||||
|
|
||||||
if (!o.all_of<Components::FT1ChunkSHA1Cache, Components::FT1InfoSHA1>()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!o.get<Components::FT1ChunkSHA1Cache>().have_all) {
|
|
||||||
participating_unfinished.emplace(o, ParticipationEntry{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ChunkPicker::ContentChunkR> ChunkPicker::updateChunkRequests(
|
|
||||||
Contact3Handle c,
|
|
||||||
ObjectRegistry& objreg,
|
|
||||||
ReceivingTransfers& rt
|
|
||||||
//NGCFT1& nft
|
|
||||||
) {
|
|
||||||
if (!static_cast<bool>(c)) {
|
|
||||||
assert(false); return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c.all_of<Contact::Components::ToxGroupPeerEphemeral>()) {
|
|
||||||
assert(false); return {};
|
|
||||||
}
|
|
||||||
const auto [group_number, peer_number] = c.get<Contact::Components::ToxGroupPeerEphemeral>();
|
|
||||||
|
|
||||||
std::vector<ContentChunkR> req_ret;
|
|
||||||
|
|
||||||
// count running tf and open requests
|
|
||||||
const size_t num_ongoing_transfers = rt.sizePeer(group_number, peer_number);
|
|
||||||
// TODO: account for open requests
|
|
||||||
// TODO: base max on rate(chunks per sec), gonna be ass with variable chunk size
|
|
||||||
const size_t num_requests = std::max<int64_t>(0, max_tf_chunk_requests-num_ongoing_transfers);
|
|
||||||
|
|
||||||
// while n < X
|
|
||||||
|
|
||||||
if (participating_unfinished.empty()) {
|
|
||||||
participating_in_last = entt::null;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// round robin content (remember last obj)
|
|
||||||
if (!objreg.valid(participating_in_last) || !participating_unfinished.count(participating_in_last)) {
|
|
||||||
participating_in_last = participating_unfinished.begin()->first;
|
|
||||||
//participating_in_last = *participating_unfinished.begin();
|
|
||||||
}
|
|
||||||
assert(objreg.valid(participating_in_last));
|
|
||||||
|
|
||||||
auto it = participating_unfinished.find(participating_in_last);
|
|
||||||
// hard limit robin rounds to array size time 100
|
|
||||||
for (size_t i = 0; req_ret.size() < num_requests && i < participating_unfinished.size()*100; i++) {
|
|
||||||
if (it == participating_unfinished.end()) {
|
|
||||||
it = participating_unfinished.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->second.skips < it->second.should_skip) {
|
|
||||||
it->second.skips++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectHandle o {objreg, it->first};
|
|
||||||
|
|
||||||
// intersect self have with other have
|
|
||||||
if (!o.all_of<Components::RemoteHave, Components::FT1ChunkSHA1Cache, Components::FT1InfoSHA1>()) {
|
|
||||||
// rare case where no one other has anything
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& cc = o.get<Components::FT1ChunkSHA1Cache>();
|
|
||||||
if (cc.have_all) {
|
|
||||||
std::cerr << "ChunkPicker error: completed content still in participating_unfinished!\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& others_have = o.get<Components::RemoteHave>().others;
|
|
||||||
auto other_it = others_have.find(c);
|
|
||||||
if (other_it == others_have.end()) {
|
|
||||||
// rare case where the other is participating but has nothing
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& other_have = other_it->second;
|
|
||||||
|
|
||||||
BitSet chunk_candidates = cc.have_chunk;
|
|
||||||
if (!other_have.have_all) {
|
|
||||||
// AND is the same as ~(~A | ~B)
|
|
||||||
// that means we leave chunk_candidates as (have is inverted want)
|
|
||||||
// merge is or
|
|
||||||
// invert at the end
|
|
||||||
chunk_candidates
|
|
||||||
.merge(other_have.have.invert())
|
|
||||||
.invert();
|
|
||||||
// TODO: add intersect for more perf
|
|
||||||
} else {
|
|
||||||
chunk_candidates.invert();
|
|
||||||
}
|
|
||||||
const auto total_chunks = o.get<Components::FT1InfoSHA1>().chunks.size();
|
|
||||||
auto& requested_chunks = o.get_or_emplace<Components::FT1ChunkSHA1Requested>().chunks;
|
|
||||||
|
|
||||||
// TODO: trim off round up to 8, since they are now always set
|
|
||||||
|
|
||||||
// now select (globaly) unrequested other have
|
|
||||||
// TODO: pick strategies
|
|
||||||
// TODO: how do we prioratize within a file?
|
|
||||||
// - first (walk from start (or readhead?))
|
|
||||||
// - random (choose random start pos and walk)
|
|
||||||
// - rarest (keep track of rarity and sort by that)
|
|
||||||
// - steaming (use read head to determain time critical chunks, potentially over requesting, first (relative to stream head) otherwise
|
|
||||||
// maybe look into libtorrens deadline stuff
|
|
||||||
// - arbitrary priority maps/functions (and combine with above in rations)
|
|
||||||
|
|
||||||
// simple, we use first
|
|
||||||
for (size_t i = 0; i < total_chunks && req_ret.size() < num_requests && i < chunk_candidates.size_bits(); i++) {
|
|
||||||
if (!chunk_candidates[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// i is a candidate we can request form peer
|
|
||||||
|
|
||||||
// first check against double requests
|
|
||||||
if (std::find_if(req_ret.cbegin(), req_ret.cend(), [&](const auto& x) -> bool {
|
|
||||||
return false;
|
|
||||||
}) != req_ret.cend()) {
|
|
||||||
// already in return array
|
|
||||||
// how did we get here? should we fast exit? if simple-first strat, we would want to
|
|
||||||
continue; // skip
|
|
||||||
}
|
|
||||||
|
|
||||||
// second check against global requests (this might differ based on strat)
|
|
||||||
if (requested_chunks.count(i) != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// third we check against globally running transfers (this might differ based on strat)
|
|
||||||
if (rt.containsChunk(o, i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if nothing else blocks this, add to ret
|
|
||||||
req_ret.push_back(ContentChunkR{o, i});
|
|
||||||
|
|
||||||
assert(requested_chunks.count(i) == 0);
|
|
||||||
requested_chunks[i] = 0.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- no -- (just compat with old code, ignore)
|
|
||||||
// if n < X
|
|
||||||
// optimistically request 1 chunk other does not have
|
|
||||||
// (don't mark es requested? or lower cooldown to re-request?)
|
|
||||||
|
|
||||||
return req_ret;
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <solanaceae/contact/contact_model3.hpp>
|
|
||||||
#include <solanaceae/object_store/object_store.hpp>
|
|
||||||
|
|
||||||
#include "./components.hpp"
|
|
||||||
|
|
||||||
#include "./receiving_transfers.hpp"
|
|
||||||
|
|
||||||
#include <entt/container/dense_map.hpp>
|
|
||||||
#include <entt/container/dense_set.hpp>
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
//#include <solanaceae/ngc_ft1/ngcft1.hpp>
|
|
||||||
|
|
||||||
// goal is to always keep 2 transfers running and X(6) requests queued up
|
|
||||||
// per peer
|
|
||||||
|
|
||||||
// contact component?
|
|
||||||
struct ChunkPicker {
|
|
||||||
// max transfers
|
|
||||||
static constexpr size_t max_tf_info_requests {1};
|
|
||||||
static constexpr size_t max_tf_chunk_requests {2};
|
|
||||||
|
|
||||||
// max outstanding requests
|
|
||||||
// TODO: should this include transfers?
|
|
||||||
static constexpr size_t max_open_info_requests {1};
|
|
||||||
const size_t max_open_chunk_requests {6};
|
|
||||||
|
|
||||||
// TODO: handle with hash utils?
|
|
||||||
struct ParticipationEntry {
|
|
||||||
ParticipationEntry(void) {}
|
|
||||||
// skips in round robin -> lower should_skip => higher priority
|
|
||||||
uint16_t should_skip {2}; // 0 high, 8 low (double each time? 0,1,2,4,8)
|
|
||||||
uint16_t skips {2};
|
|
||||||
};
|
|
||||||
// TODO: only unfinished?
|
|
||||||
entt::dense_map<Object, ParticipationEntry> participating_unfinished;
|
|
||||||
entt::dense_set<Object> participating;
|
|
||||||
Object participating_in_last {entt::null};
|
|
||||||
|
|
||||||
void updateParticipation(
|
|
||||||
Contact3Handle c,
|
|
||||||
ObjectRegistry& objreg
|
|
||||||
);
|
|
||||||
|
|
||||||
// tick
|
|
||||||
//void sendInfoRequests();
|
|
||||||
// is this like a system?
|
|
||||||
// TODO: only update on:
|
|
||||||
// - transfer start?
|
|
||||||
// - transfer done
|
|
||||||
// - request timed out
|
|
||||||
// - reset on disconnect?
|
|
||||||
struct ContentChunkR {
|
|
||||||
ObjectHandle object;
|
|
||||||
size_t chunk_index;
|
|
||||||
};
|
|
||||||
// returns list of chunks to request
|
|
||||||
[[nodiscard]] std::vector<ContentChunkR> updateChunkRequests(
|
|
||||||
Contact3Handle c,
|
|
||||||
ObjectRegistry& objreg,
|
|
||||||
ReceivingTransfers& rt
|
|
||||||
//NGCFT1& nft
|
|
||||||
);
|
|
||||||
|
|
||||||
// - reset on disconnect?
|
|
||||||
void resetPeer(
|
|
||||||
Contact3Handle c
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
#include "./components.hpp"
|
|
||||||
|
|
||||||
std::vector<size_t> Components::FT1ChunkSHA1Cache::chunkIndices(const SHA1Digest& hash) const {
|
|
||||||
const auto it = chunk_hash_to_index.find(hash);
|
|
||||||
if (it != chunk_hash_to_index.cend()) {
|
|
||||||
return it->second;
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Components::FT1ChunkSHA1Cache::haveChunk(const SHA1Digest& hash) const {
|
|
||||||
if (have_all) { // short cut
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto i_vec = chunkIndices(hash); !i_vec.empty()) {
|
|
||||||
// TODO: should i test all?
|
|
||||||
return have_chunk[i_vec.front()];
|
|
||||||
}
|
|
||||||
|
|
||||||
// not part of this file
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <solanaceae/contact/components.hpp>
|
|
||||||
#include <solanaceae/message3/components.hpp>
|
|
||||||
#include <solanaceae/message3/registry_message_model.hpp>
|
|
||||||
|
|
||||||
#include <solanaceae/util/bitset.hpp>
|
|
||||||
|
|
||||||
#include <entt/container/dense_set.hpp>
|
|
||||||
|
|
||||||
#include "./ft1_sha1_info.hpp"
|
|
||||||
#include "./hash_utils.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: rename to object components
|
|
||||||
namespace Components {
|
|
||||||
|
|
||||||
struct Messages {
|
|
||||||
// dense set instead?
|
|
||||||
std::vector<Message3Handle> messages;
|
|
||||||
};
|
|
||||||
|
|
||||||
using FT1InfoSHA1 = FT1InfoSHA1;
|
|
||||||
|
|
||||||
struct FT1InfoSHA1Data {
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FT1InfoSHA1Hash {
|
|
||||||
std::vector<uint8_t> hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FT1ChunkSHA1Cache {
|
|
||||||
// TODO: extract have_chunk, have_all and have_count to generic comp
|
|
||||||
|
|
||||||
// have_chunk is the size of info.chunks.size(), or empty if have_all
|
|
||||||
// keep in mind bitset rounds up to 8s
|
|
||||||
BitSet have_chunk{0};
|
|
||||||
|
|
||||||
bool have_all {false};
|
|
||||||
size_t have_count {0};
|
|
||||||
entt::dense_map<SHA1Digest, std::vector<size_t>> chunk_hash_to_index;
|
|
||||||
|
|
||||||
std::vector<size_t> chunkIndices(const SHA1Digest& hash) const;
|
|
||||||
bool haveChunk(const SHA1Digest& hash) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FT1ChunkSHA1Requested {
|
|
||||||
// requested chunks with a timer since last request
|
|
||||||
entt::dense_map<size_t, float> chunks;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: once announce is shipped, remove the "Suspected"
|
|
||||||
struct SuspectedParticipants {
|
|
||||||
entt::dense_set<Contact3> participants;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RemoteHave {
|
|
||||||
struct Entry {
|
|
||||||
bool have_all {false};
|
|
||||||
BitSet have;
|
|
||||||
};
|
|
||||||
entt::dense_map<Contact3, Entry> others;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReRequestInfoTimer {
|
|
||||||
float timer {0.f};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReadHeadHint {
|
|
||||||
// points to the first byte we want
|
|
||||||
// this is just a hint, that can be set from outside
|
|
||||||
// to guide the sequential "piece picker" strategy
|
|
||||||
// the strategy *should* set this to the first byte we dont yet have
|
|
||||||
uint64_t offset_into_file {0u};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Components
|
|
||||||
|
|
@ -18,7 +18,7 @@ struct SHA1Digest {
|
|||||||
bool operator==(const SHA1Digest& other) const { return data == other.data; }
|
bool operator==(const SHA1Digest& other) const { return data == other.data; }
|
||||||
bool operator!=(const SHA1Digest& other) const { return data != other.data; }
|
bool operator!=(const SHA1Digest& other) const { return data != other.data; }
|
||||||
|
|
||||||
constexpr size_t size(void) const { return data.size(); }
|
size_t size(void) const { return data.size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const SHA1Digest& v);
|
std::ostream& operator<<(std::ostream& out, const SHA1Digest& v);
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
#include "./participation.hpp"
|
|
||||||
|
|
||||||
#include "./chunk_picker.hpp"
|
|
||||||
|
|
||||||
bool addParticipation(Contact3Handle c, ObjectHandle o) {
|
|
||||||
bool was_new {false};
|
|
||||||
|
|
||||||
if (static_cast<bool>(o)) {
|
|
||||||
const auto [_, inserted] = o.get_or_emplace<Components::SuspectedParticipants>().participants.emplace(c);
|
|
||||||
was_new = inserted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<bool>(c)) {
|
|
||||||
const auto [_, inserted] = c.get_or_emplace<ChunkPicker>().participating.emplace(o);
|
|
||||||
was_new = was_new || inserted;
|
|
||||||
|
|
||||||
// TODO: if not have_all
|
|
||||||
c.get_or_emplace<ChunkPicker>().participating_unfinished.emplace(o, ChunkPicker::ParticipationEntry{});
|
|
||||||
}
|
|
||||||
|
|
||||||
return was_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeParticipation(Contact3Handle c, ObjectHandle o) {
|
|
||||||
if (static_cast<bool>(o) && o.all_of<Components::SuspectedParticipants>()) {
|
|
||||||
o.get<Components::SuspectedParticipants>().participants.erase(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<bool>(c) && c.all_of<ChunkPicker>()) {
|
|
||||||
c.get<ChunkPicker>().participating.erase(o);
|
|
||||||
c.get<ChunkPicker>().participating_unfinished.erase(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <solanaceae/object_store/object_store.hpp>
|
|
||||||
#include <solanaceae/contact/contact_model3.hpp>
|
|
||||||
|
|
||||||
bool addParticipation(Contact3Handle c, ObjectHandle o);
|
|
||||||
void removeParticipation(Contact3Handle c, ObjectHandle o);
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
|||||||
#include "./receiving_transfers.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
void ReceivingTransfers::tick(float delta) {
|
|
||||||
for (auto peer_it = _data.begin(); peer_it != _data.end();) {
|
|
||||||
for (auto it = peer_it->second.begin(); it != peer_it->second.end();) {
|
|
||||||
it->second.time_since_activity += delta;
|
|
||||||
|
|
||||||
// if we have not heard for 20sec, timeout
|
|
||||||
if (it->second.time_since_activity >= 20.f) {
|
|
||||||
std::cerr << "SHA1_NGCFT1 warning: receiving tansfer timed out " << "." << int(it->first) << "\n";
|
|
||||||
// TODO: if info, requeue? or just keep the timer comp? - no, timer comp will continue ticking, even if loading
|
|
||||||
//it->second.v
|
|
||||||
it = peer_it->second.erase(it);
|
|
||||||
} else {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peer_it->second.empty()) {
|
|
||||||
// cleanup unused peers too agressive?
|
|
||||||
peer_it = _data.erase(peer_it);
|
|
||||||
} else {
|
|
||||||
peer_it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReceivingTransfers::Entry& ReceivingTransfers::emplaceInfo(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, const Entry::Info& info) {
|
|
||||||
auto& ent = _data[combine_ids(group_number, peer_number)][transfer_id];
|
|
||||||
ent.v = info;
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReceivingTransfers::Entry& ReceivingTransfers::emplaceChunk(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, const Entry::Chunk& chunk) {
|
|
||||||
assert(!chunk.chunk_indices.empty());
|
|
||||||
assert(!containsPeerChunk(group_number, peer_number, chunk.content, chunk.chunk_indices.front()));
|
|
||||||
auto& ent = _data[combine_ids(group_number, peer_number)][transfer_id];
|
|
||||||
ent.v = chunk;
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReceivingTransfers::containsPeerTransfer(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id) const {
|
|
||||||
auto it = _data.find(combine_ids(group_number, peer_number));
|
|
||||||
if (it == _data.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return it->second.count(transfer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReceivingTransfers::containsChunk(ObjectHandle o, size_t chunk_idx) const {
|
|
||||||
for (const auto& [_, p] : _data) {
|
|
||||||
for (const auto& [_2, v] : p) {
|
|
||||||
if (!v.isChunk()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& c = v.getChunk();
|
|
||||||
if (c.content != o) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto idx : c.chunk_indices) {
|
|
||||||
if (idx == chunk_idx) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReceivingTransfers::containsPeerChunk(uint32_t group_number, uint32_t peer_number, ObjectHandle o, size_t chunk_idx) const {
|
|
||||||
auto it = _data.find(combine_ids(group_number, peer_number));
|
|
||||||
if (it == _data.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& [_, v] : it->second) {
|
|
||||||
if (!v.isChunk()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& c = v.getChunk();
|
|
||||||
if (c.content != o) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto idx : c.chunk_indices) {
|
|
||||||
if (idx == chunk_idx) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceivingTransfers::removePeer(uint32_t group_number, uint32_t peer_number) {
|
|
||||||
_data.erase(combine_ids(group_number, peer_number));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceivingTransfers::removePeerTransfer(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id) {
|
|
||||||
auto it = _data.find(combine_ids(group_number, peer_number));
|
|
||||||
if (it == _data.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
it->second.erase(transfer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ReceivingTransfers::size(void) const {
|
|
||||||
size_t count {0};
|
|
||||||
for (const auto& [_, p] : _data) {
|
|
||||||
count += p.size();
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ReceivingTransfers::sizePeer(uint32_t group_number, uint32_t peer_number) const {
|
|
||||||
auto it = _data.find(combine_ids(group_number, peer_number));
|
|
||||||
if (it == _data.end()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return it->second.size();
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <solanaceae/object_store/object_store.hpp>
|
|
||||||
|
|
||||||
#include <entt/container/dense_map.hpp>
|
|
||||||
|
|
||||||
#include "./util.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct ReceivingTransfers {
|
|
||||||
struct Entry {
|
|
||||||
struct Info {
|
|
||||||
ObjectHandle content;
|
|
||||||
// copy of info data
|
|
||||||
// too large?
|
|
||||||
std::vector<uint8_t> info_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Chunk {
|
|
||||||
ObjectHandle content;
|
|
||||||
std::vector<size_t> chunk_indices;
|
|
||||||
// or data?
|
|
||||||
// if memmapped, this would be just a pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
std::variant<Info, Chunk> v;
|
|
||||||
|
|
||||||
float time_since_activity {0.f};
|
|
||||||
|
|
||||||
bool isInfo(void) const { return std::holds_alternative<Info>(v); }
|
|
||||||
bool isChunk(void) const { return std::holds_alternative<Chunk>(v); }
|
|
||||||
|
|
||||||
Info& getInfo(void) { return std::get<Info>(v); }
|
|
||||||
const Info& getInfo(void) const { return std::get<Info>(v); }
|
|
||||||
Chunk& getChunk(void) { return std::get<Chunk>(v); }
|
|
||||||
const Chunk& getChunk(void) const { return std::get<Chunk>(v); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// key is groupid + peerid
|
|
||||||
// TODO: replace with contact
|
|
||||||
//using ReceivingTransfers = entt::dense_map<uint64_t, entt::dense_map<uint8_t, ReceivingTransferE>>;
|
|
||||||
entt::dense_map<uint64_t, entt::dense_map<uint8_t, Entry>> _data;
|
|
||||||
|
|
||||||
void tick(float delta);
|
|
||||||
|
|
||||||
Entry& emplaceInfo(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, const Entry::Info& info);
|
|
||||||
Entry& emplaceChunk(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id, const Entry::Chunk& chunk);
|
|
||||||
|
|
||||||
bool containsPeer(uint32_t group_number, uint32_t peer_number) const { return _data.count(combine_ids(group_number, peer_number)); }
|
|
||||||
bool containsPeerTransfer(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id) const;
|
|
||||||
bool containsChunk(ObjectHandle o, size_t chunk_idx) const;
|
|
||||||
bool containsPeerChunk(uint32_t group_number, uint32_t peer_number, ObjectHandle o, size_t chunk_idx) const;
|
|
||||||
|
|
||||||
auto& getPeer(uint32_t group_number, uint32_t peer_number) { return _data.at(combine_ids(group_number, peer_number)); }
|
|
||||||
auto& getTransfer(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id) { return getPeer(group_number, peer_number).at(transfer_id); }
|
|
||||||
|
|
||||||
void removePeer(uint32_t group_number, uint32_t peer_number);
|
|
||||||
void removePeerTransfer(uint32_t group_number, uint32_t peer_number, uint8_t transfer_id);
|
|
||||||
|
|
||||||
size_t size(void) const;
|
|
||||||
size_t sizePeer(uint32_t group_number, uint32_t peer_number) const;
|
|
||||||
};
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@
|
|||||||
#include <solanaceae/ngc_ft1/ngcft1.hpp>
|
#include <solanaceae/ngc_ft1/ngcft1.hpp>
|
||||||
|
|
||||||
#include "./ft1_sha1_info.hpp"
|
#include "./ft1_sha1_info.hpp"
|
||||||
#include "./receiving_transfers.hpp"
|
|
||||||
|
|
||||||
#include <entt/entity/registry.hpp>
|
#include <entt/entity/registry.hpp>
|
||||||
#include <entt/entity/handle.hpp>
|
#include <entt/entity/handle.hpp>
|
||||||
@ -22,15 +21,13 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public NGCFT1EventI, public NGCEXTEventI {
|
class SHA1_NGCFT1 : public RegistryMessageModelEventI, public NGCFT1EventI {
|
||||||
ObjectStore2& _os;
|
ObjectStore2& _os;
|
||||||
// TODO: backend abstraction
|
// TODO: backend abstraction
|
||||||
Contact3Registry& _cr;
|
Contact3Registry& _cr;
|
||||||
RegistryMessageModel& _rmm;
|
RegistryMessageModel& _rmm;
|
||||||
NGCFT1& _nft;
|
NGCFT1& _nft;
|
||||||
ToxContactModel2& _tcm;
|
ToxContactModel2& _tcm;
|
||||||
ToxEventProviderI& _tep;
|
|
||||||
NGCEXTEventProvider& _neep;
|
|
||||||
|
|
||||||
std::minstd_rand _rng {1337*11};
|
std::minstd_rand _rng {1337*11};
|
||||||
|
|
||||||
@ -69,7 +66,27 @@ class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public
|
|||||||
// key is groupid + peerid
|
// key is groupid + peerid
|
||||||
entt::dense_map<uint64_t, entt::dense_map<uint8_t, SendingTransfer>> _sending_transfers;
|
entt::dense_map<uint64_t, entt::dense_map<uint8_t, SendingTransfer>> _sending_transfers;
|
||||||
|
|
||||||
ReceivingTransfers _receiving_transfers;
|
struct ReceivingTransfer {
|
||||||
|
struct Info {
|
||||||
|
ObjectHandle content;
|
||||||
|
// copy of info data
|
||||||
|
// too large?
|
||||||
|
std::vector<uint8_t> info_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
ObjectHandle content;
|
||||||
|
std::vector<size_t> chunk_indices;
|
||||||
|
// or data?
|
||||||
|
// if memmapped, this would be just a pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
std::variant<Info, Chunk> v;
|
||||||
|
|
||||||
|
float time_since_activity {0.f};
|
||||||
|
};
|
||||||
|
// key is groupid + peerid
|
||||||
|
entt::dense_map<uint64_t, entt::dense_map<uint8_t, ReceivingTransfer>> _receiving_transfers;
|
||||||
|
|
||||||
// makes request rotate around open content
|
// makes request rotate around open content
|
||||||
std::deque<ObjectHandle> _queue_content_want_info;
|
std::deque<ObjectHandle> _queue_content_want_info;
|
||||||
@ -77,9 +94,16 @@ class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public
|
|||||||
|
|
||||||
std::atomic_bool _info_builder_dirty {false};
|
std::atomic_bool _info_builder_dirty {false};
|
||||||
std::mutex _info_builder_queue_mutex;
|
std::mutex _info_builder_queue_mutex;
|
||||||
|
//struct InfoBuilderEntry {
|
||||||
|
//// called on completion on the iterate thread
|
||||||
|
//// (owning)
|
||||||
|
//std::function<void(void)> fn;
|
||||||
|
//};
|
||||||
using InfoBuilderEntry = std::function<void(void)>;
|
using InfoBuilderEntry = std::function<void(void)>;
|
||||||
std::list<InfoBuilderEntry> _info_builder_queue;
|
std::list<InfoBuilderEntry> _info_builder_queue;
|
||||||
|
|
||||||
|
static uint64_t combineIds(const uint32_t group_number, const uint32_t peer_number);
|
||||||
|
|
||||||
void updateMessages(ObjectHandle ce);
|
void updateMessages(ObjectHandle ce);
|
||||||
|
|
||||||
std::optional<std::pair<uint32_t, uint32_t>> selectPeerForRequest(ObjectHandle ce);
|
std::optional<std::pair<uint32_t, uint32_t>> selectPeerForRequest(ObjectHandle ce);
|
||||||
@ -87,8 +111,10 @@ class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public
|
|||||||
public: // TODO: config
|
public: // TODO: config
|
||||||
bool _udp_only {false};
|
bool _udp_only {false};
|
||||||
|
|
||||||
size_t _max_concurrent_in {4};
|
size_t _max_concurrent_in {6};
|
||||||
size_t _max_concurrent_out {4};
|
size_t _max_concurrent_out {8};
|
||||||
|
// TODO: probably also includes running transfers rn (meh)
|
||||||
|
size_t _max_pending_requests {32}; // per content
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SHA1_NGCFT1(
|
SHA1_NGCFT1(
|
||||||
@ -96,9 +122,7 @@ class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public
|
|||||||
Contact3Registry& cr,
|
Contact3Registry& cr,
|
||||||
RegistryMessageModel& rmm,
|
RegistryMessageModel& rmm,
|
||||||
NGCFT1& nft,
|
NGCFT1& nft,
|
||||||
ToxContactModel2& tcm,
|
ToxContactModel2& tcm
|
||||||
ToxEventProviderI& tep,
|
|
||||||
NGCEXTEventProvider& neep
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void iterate(float delta);
|
void iterate(float delta);
|
||||||
@ -116,12 +140,5 @@ class SHA1_NGCFT1 : public ToxEventI, public RegistryMessageModelEventI, public
|
|||||||
bool onEvent(const Events::NGCFT1_recv_message&) override;
|
bool onEvent(const Events::NGCFT1_recv_message&) override;
|
||||||
|
|
||||||
bool sendFilePath(const Contact3 c, std::string_view file_name, std::string_view file_path) override;
|
bool sendFilePath(const Contact3 c, std::string_view file_name, std::string_view file_path) override;
|
||||||
|
|
||||||
bool onToxEvent(const Tox_Event_Group_Peer_Exit* e) override;
|
|
||||||
|
|
||||||
bool onEvent(const Events::NGCEXT_ft1_have&) override;
|
|
||||||
bool onEvent(const Events::NGCEXT_ft1_bitset&) override;
|
|
||||||
|
|
||||||
bool onEvent(const Events::NGCEXT_pc1_announce&) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
inline static uint64_t combine_ids(const uint32_t group_number, const uint32_t peer_number) {
|
|
||||||
return (uint64_t(group_number) << 32) | peer_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void decompose_ids(const uint64_t combined_id, uint32_t& group_number, uint32_t& peer_number) {
|
|
||||||
group_number = combined_id >> 32;
|
|
||||||
peer_number = combined_id & 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
Reference in New Issue
Block a user