From 41150a033241dad2983b59d97f3b56d911065778 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Mon, 3 Oct 2022 23:33:08 +0200 Subject: [PATCH] wip send file request --- ngc_ext_common.hpp | 46 +++++++++++------------ ngc_ft1.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++- ngc_ft1.h | 50 ++++++++++++++++++++++++- ngc_hs1.cpp | 85 ++++++++++++++++++++++++++++++++++++++---- ngc_hs1.h | 2 + 5 files changed, 243 insertions(+), 32 deletions(-) diff --git a/ngc_ext_common.hpp b/ngc_ext_common.hpp index 5472379..cac4324 100644 --- a/ngc_ext_common.hpp +++ b/ngc_ext_common.hpp @@ -22,7 +22,7 @@ enum _PacketType : uint8_t { // request last (few) message_ids for a peer // - peer_key bytes (peer key we want to know ids for) // - 1 byte (uint8_t count ids, atleast 1) - HS1_REQUEST_LAST_IDS, + HS1_REQUEST_LAST_IDS = 1u, // respond to a request with 0 or more message ids, sorted by newest first // - peer_key bytes (the msg_ids are from) @@ -35,7 +35,7 @@ enum _PacketType : uint8_t { // request the other side to initiate a FT // - 1 byte (file_kind) // - X bytes (file_kind dependent id, differnt sizes) - FT1_REQUEST, + FT1_REQUEST = 8u, // tell the other side you want to start a FT // TODO: might use id layer instead. with it, it would look similar to friends_ft @@ -74,27 +74,6 @@ enum _PacketType : uint8_t { FT1_DATA_FIN_ACK, }; -static const char* _pkgid2str(_PacketType type) { -#define _EXT_CASE(x) case (x): return #x; - switch (type) { - _EXT_CASE(INVALID) - - _EXT_CASE(HS1_REQUEST_LAST_IDS) - _EXT_CASE(HS1_RESPONSE_LAST_IDS) - - _EXT_CASE(FT1_REQUEST) - _EXT_CASE(FT1_INIT) - _EXT_CASE(FT1_INIT_ACK) - _EXT_CASE(FT1_DATA) - _EXT_CASE(FT1_DATA_ACK) - _EXT_CASE(FT1_DATA_FIN) - _EXT_CASE(FT1_DATA_FIN_ACK) - - default: return ""; - } -#undef _EXT_CASE -} - struct _GroupKey { std::array data; @@ -135,3 +114,24 @@ struct NGC_EXT_CTX { NGC_FT1* ngc_ft1_ctx = nullptr; }; +[[maybe_unused]] static const char* _pkgid2str(_PacketType type) { +#define _EXT_CASE(x) case (x): return #x; + switch (type) { + _EXT_CASE(INVALID) + + _EXT_CASE(HS1_REQUEST_LAST_IDS) + _EXT_CASE(HS1_RESPONSE_LAST_IDS) + + _EXT_CASE(FT1_REQUEST) + _EXT_CASE(FT1_INIT) + _EXT_CASE(FT1_INIT_ACK) + _EXT_CASE(FT1_DATA) + _EXT_CASE(FT1_DATA_ACK) + _EXT_CASE(FT1_DATA_FIN) + _EXT_CASE(FT1_DATA_FIN_ACK) + + default: return ""; + } +#undef _EXT_CASE +} + diff --git a/ngc_ft1.cpp b/ngc_ft1.cpp index 1ff73ff..bb4a37d 100644 --- a/ngc_ft1.cpp +++ b/ngc_ft1.cpp @@ -2,16 +2,27 @@ #include "ngc_ext_common.hpp" +#include +#include + struct NGC_FT1 { NGC_FT1_options options; }; +static void _handle_FT1_REQUEST(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_INIT(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_INIT_ACK(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_DATA(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_DATA_ACK(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_DATA_FIN(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); +//static void _handle_FT1_DATA_FIN_ACK(Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length); + bool NGC_FT1_init(NGC_EXT_CTX* ngc_ext_ctx, const struct NGC_FT1_options* options) { ngc_ext_ctx->ngc_ft1_ctx = new NGC_FT1; ngc_ext_ctx->ngc_ft1_ctx->options = *options; - ngc_ext_ctx->callbacks[FT1_REQUEST] = nullptr; + ngc_ext_ctx->callbacks[FT1_REQUEST] = _handle_FT1_REQUEST; ngc_ext_ctx->callbacks[FT1_INIT] = nullptr; ngc_ext_ctx->callbacks[FT1_INIT_ACK] = nullptr; ngc_ext_ctx->callbacks[FT1_DATA] = nullptr; @@ -29,3 +40,82 @@ void NGC_FT1_kill(NGC_EXT_CTX* ngc_ext_ctx) { ngc_ext_ctx->ngc_ft1_ctx = nullptr; } +// iterate + +void NGC_FT1_request( + Tox *tox, NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + + NGC_FT1_file_kind file_kind, + + const uint8_t* file_id, + size_t file_id_size +) { + // just call private for every peer in group? + for (;;) { + uint32_t peer_number = 0; + NGC_FT1_request_private(tox, ngc_ext_ctx, group_number, peer_number, file_kind, file_id, file_id_size); + assert(false && "not implemented"); + } +} + +void NGC_FT1_request_private( + Tox *tox, NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + uint32_t peer_number, + + NGC_FT1_file_kind file_kind, + + const uint8_t* file_id, + size_t file_id_size +) { + assert(tox); + assert(ngc_ext_ctx); + assert(ngc_ext_ctx->ngc_ft1_ctx); + + // record locally that we sent(or want to send) the request? + + // - 1 byte packet id + // - 1 byte (TODO: more?) file_kind + // - X bytes file_id + std::vector pkg; + pkg.push_back(FT1_REQUEST); + pkg.push_back(file_kind); + for (size_t i = 0; i < file_id_size; i++) { + pkg.push_back(file_id[i]); + } + + // lossless + tox_group_send_custom_private_packet(tox, group_number, peer_number, true, pkg.data(), pkg.size(), nullptr); +} + +#define _DATA_HAVE(x, error) if ((length - curser) < (x)) { error; } + +static void _handle_FT1_REQUEST( + Tox* tox, + NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + uint32_t peer_number, + + const uint8_t *data, + size_t length +) { + size_t curser = 0; + + // TODO: might be uint16_t or even larger + uint8_t file_kind; + _DATA_HAVE(sizeof(file_kind), fprintf(stderr, "packet too small, missing file_kind\n"); return) + file_kind = data[curser++]; + + fprintf(stderr, "got FT request with file_kind %u [", file_kind); + for (; curser < length; curser++) { + fprintf(stderr, "%02X", data[curser]); + } + fprintf(stderr, "]\n"); +} + +#undef _DATA_HAVE + diff --git a/ngc_ft1.h b/ngc_ft1.h index 00fc5ae..ce5b405 100644 --- a/ngc_ft1.h +++ b/ngc_ft1.h @@ -20,13 +20,61 @@ struct NGC_FT1_options { int tmp; }; +// uint16_t ? +// ffs c does not allow types +typedef enum NGC_FT1_file_kind /*: uint8_t*/ { + //INVALID = 0u, + + // id: + // group (implicit) + // peer pub key + msg_id + NGC_HS1_MESSAGE_BY_ID = 1u, // history sync PoC 1 + + // :) + // draft for fun and profit + // id: infohash + TORRENT_V1_METAINFO, + // id: infohash + TORRENT_V2_METAINFO, + // id: sha1 + TORRENT_V1_CHUNK, + // id: sha256 + TORRENT_V2_CHUNK, +} NGC_FT1_file_kind; + // ========== init / kill ========== // (see tox api) bool NGC_FT1_init(NGC_EXT_CTX* ngc_ext_ctx, const struct NGC_FT1_options* options); void NGC_FT1_kill(NGC_EXT_CTX* ngc_ext_ctx); // ========== iterate ========== -void NGC_FT1_iterate(Tox *tox, NGC_FT1* ngc_hs1_ctx/*, void *user_data*/); +void NGC_FT1_iterate(Tox *tox, NGC_EXT_CTX* ngc_ext_ctx/*, void *user_data*/); + +// ========== request ========== + +// TODO: remove? +void NGC_FT1_request( + Tox *tox, NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + + NGC_FT1_file_kind file_kind, + + const uint8_t* file_id, + size_t file_id_size +); + +void NGC_FT1_request_private( + Tox *tox, NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + uint32_t peer_number, + + NGC_FT1_file_kind file_kind, + + const uint8_t* file_id, + size_t file_id_size +); // ========== peer online/offline ========== diff --git a/ngc_hs1.cpp b/ngc_hs1.cpp index 363f875..6e0dc3f 100644 --- a/ngc_hs1.cpp +++ b/ngc_hs1.cpp @@ -1,6 +1,7 @@ #include "./ngc_hs1.h" #include "ngc_ext_common.hpp" +#include "ngc_ft1.h" #include #include @@ -34,6 +35,12 @@ struct NGC_HS1 { // msg_ids we have only heard of, with peer_number of who we heard it from std::map> heard_of; + struct PendingFTRequest { + uint32_t peer_number; // the peer we requested the message from + float time_since_ft_activity {0.f}; + }; + std::map pending; + // dont start immediatly float time_since_last_request_sent {0.f}; @@ -124,7 +131,9 @@ void NGC_HS1_kill(NGC_EXT_CTX* ngc_ext_ctx) { ngc_ext_ctx->ngc_hs1_ctx = nullptr; } -static void _iterate_group(Tox *tox, NGC_HS1* ngc_hs1_ctx, uint32_t group_number, float time_delta) { +static void _iterate_group(Tox *tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, float time_delta) { + NGC_HS1* ngc_hs1_ctx = ngc_ext_ctx->ngc_hs1_ctx; + //fprintf(stderr, "g:%u\n", g_i); _GroupKey g_id{}; { // TODO: error @@ -144,13 +153,13 @@ static void _iterate_group(Tox *tox, NGC_HS1* ngc_hs1_ctx, uint32_t group_number auto& group = ngc_hs1_ctx->history[g_id]; // for each peer - for (auto& [key, peer] : group.peers) { + for (auto& [peer_key, peer] : group.peers) { //fprintf(stderr, " p: %X%X%X%X\n", key.data.data()[0], key.data.data()[1], key.data.data()[2], key.data.data()[3]); peer.time_since_last_request_sent += time_delta; if (peer.time_since_last_request_sent > ngc_hs1_ctx->options.query_interval_per_peer) { peer.time_since_last_request_sent = 0.f; - fprintf(stderr, "requesting ids for %X%X%X%X\n", key.data.data()[0], key.data.data()[1], key.data.data()[2], key.data.data()[3]); + fprintf(stderr, "requesting ids for %X%X%X%X\n", peer_key.data.data()[0], peer_key.data.data()[1], peer_key.data.data()[2], peer_key.data.data()[3]); // TODO: other way around? // ask everyone if they have newer stuff for this peer @@ -160,11 +169,65 @@ static void _iterate_group(Tox *tox, NGC_HS1* ngc_hs1_ctx, uint32_t group_number // - 1 byte (uint8_t count ids, atleast 1) std::array pkg; pkg[0] = HS1_REQUEST_LAST_IDS; - std::copy(key.data.begin(), key.data.end(), pkg.begin()+1); + std::copy(peer_key.data.begin(), peer_key.data.end(), pkg.begin()+1); pkg[1+TOX_GROUP_PEER_PUBLIC_KEY_SIZE] = ngc_hs1_ctx->options.last_msg_ids_count; // request last (up to) 5 msg_ids tox_group_send_custom_packet(tox, group_number, true, pkg.data(), pkg.size(), nullptr); } + + // check if pending msg requests have timed out + for (auto it = peer.pending.begin(); it != peer.pending.end();) { + it->second.time_since_ft_activity += time_delta; + if (it->second.time_since_ft_activity >= ngc_hs1_ctx->options.ft_activity_timeout) { + // timed out + fprintf(stderr, "!!! pending ft request timed out (%08X)\n", it->first); + it = peer.pending.erase(it); + } else { + it++; + } + } + + // request FT for only heard of message_ids + size_t request_made_count = 0; + for (const auto& [msg_id, remote_peer_numbers] : peer.heard_of) { + if (request_made_count >= 2) { // 2 for test + // TODO: limit requests per iterate option + break; + } + + if (peer.pending.count(msg_id)) { + continue; // allready requested + } + + if (remote_peer_numbers.empty()) { + fprintf(stderr, "!!! msg_id we heard of, but no remote peer !!!\n"); + continue; + } + + const uint32_t remote_peer_number = *remote_peer_numbers.begin(); + + // craft file id + std::array file_id{}; + { + std::copy(peer_key.data.cbegin(), peer_key.data.cend(), file_id.begin()); + + // HACK: little endian + const uint8_t* tmp_ptr = reinterpret_cast(&msg_id); + std::copy(tmp_ptr, tmp_ptr+sizeof(uint32_t), file_id.begin()+TOX_GROUP_PEER_PUBLIC_KEY_SIZE); + } + + // send request + NGC_FT1_request_private( + tox, ngc_ext_ctx, + group_number, remote_peer_number, + NGC_FT1_file_kind::NGC_HS1_MESSAGE_BY_ID, + file_id.data(), file_id.size() + ); + + peer.pending[msg_id] = {remote_peer_number, 0.f}; + + request_made_count++; + } } } assert(ngc_hs1_ctx->history.size() != 0); @@ -174,8 +237,7 @@ static void _iterate_group(Tox *tox, NGC_HS1* ngc_hs1_ctx, uint32_t group_number void NGC_HS1_iterate(Tox *tox, NGC_EXT_CTX* ngc_ext_ctx/*, void *user_data*/) { assert(ngc_ext_ctx); - NGC_HS1* ngc_hs1_ctx = ngc_ext_ctx->ngc_hs1_ctx; - assert(ngc_hs1_ctx); + assert(ngc_ext_ctx->ngc_hs1_ctx); //fprintf(stderr, "groups: %u\n", ngc_hs1_ctx->history.size()); @@ -186,7 +248,7 @@ void NGC_HS1_iterate(Tox *tox, NGC_EXT_CTX* ngc_ext_ctx/*, void *user_data*/) { if (tox_group_is_connected(tox, g_i, &g_err)) { // valid and connected here // TODO: delta time, or other timers - _iterate_group(tox, ngc_hs1_ctx, g_i, 0.02f); + _iterate_group(tox, ngc_ext_ctx, g_i, 0.02f); g_c_done++; } else if (g_err != TOX_ERR_GROUP_IS_CONNECTED_GROUP_NOT_FOUND) { g_c_done++; @@ -429,11 +491,17 @@ static void _handle_HS1_RESPONSE_LAST_IDS( // get peer auto& peer = ngc_hs1_ctx->history[g_id].peers[p_key]; + //std::vector message_ids{}; + for (size_t i = 0; i < last_msg_id_count && curser+sizeof(uint32_t) <= length; i++) { uint32_t msg_id; + // HACK: little endian std::copy(data+curser, data+curser+sizeof(uint32_t), reinterpret_cast(&msg_id)); curser += sizeof(uint32_t); + + //message_ids.push_back(msg_id); + fprintf(stderr, " %08X", msg_id); if (peer.hear(msg_id, peer_number)) { @@ -442,6 +510,9 @@ static void _handle_HS1_RESPONSE_LAST_IDS( fprintf(stderr, "\n"); } + + // TODO: replace, remote crash + assert(curser == length); } #undef _HS1_HAVE diff --git a/ngc_hs1.h b/ngc_hs1.h index e7e1be5..7774ef6 100644 --- a/ngc_hs1.h +++ b/ngc_hs1.h @@ -33,6 +33,8 @@ struct NGC_HS1_options { float query_interval_per_peer; // 15.f size_t last_msg_ids_count; // 5 + + float ft_activity_timeout; // seconds 60.f }; // ========== init / kill ==========