diff --git a/solanaceae/ngc_ext/ngcext.cpp b/solanaceae/ngc_ext/ngcext.cpp index 899becd..f38673c 100644 --- a/solanaceae/ngc_ext/ngcext.cpp +++ b/solanaceae/ngc_ext/ngcext.cpp @@ -1,5 +1,6 @@ #include "./ngcext.hpp" +#include #include NGCEXTEventProvider::NGCEXTEventProvider(ToxEventProviderI& tep) : _tep(tep) { @@ -261,6 +262,132 @@ 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( const uint32_t group_number, const uint32_t peer_number, @@ -292,6 +419,12 @@ bool NGCEXTEventProvider::handlePacket( return parse_ft1_data_ack(group_number, peer_number, data+1, data_size-1, _private); case NGCEXT_Event::FT1_MESSAGE: 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: return false; } diff --git a/solanaceae/ngc_ext/ngcext.hpp b/solanaceae/ngc_ext/ngcext.hpp index 95ab0f7..3d10b4f 100644 --- a/solanaceae/ngc_ext/ngcext.hpp +++ b/solanaceae/ngc_ext/ngcext.hpp @@ -119,7 +119,6 @@ namespace Events { // - 4 byte (message_id) uint32_t message_id; - // request the other side to initiate a FT // - 4 byte (file_kind) uint32_t file_kind; @@ -127,6 +126,49 @@ namespace Events { std::vector 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 file_id; + + // - array [ + // - 4 bytes (chunk index) + // - ] + std::vector 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 file_id; + + uint32_t start_chunk; + + // - array [ + // - 1 bit (have chunk) + // - ] (filled up with zero) + // high to low? + std::vector chunk_bitset; + }; + + struct NGCEXT_pc1_announce { + uint32_t group_number; + uint32_t peer_number; + + // - X bytes (id, differnt sizes) + std::vector id; + }; + } // Events enum class NGCEXT_Event : uint8_t { @@ -186,11 +228,44 @@ enum class NGCEXT_Event : uint8_t { // send file as message // basically the opposite of request // contains file_kind and file_id (and timestamp?) - // - 4 byte (message_id) - // - 4 byte (file_kind) + // - 4 bytes (message_id) + // - 4 bytes (file_kind) // - X bytes (file_kind dependent id, differnt sizes) 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 }; @@ -204,6 +279,9 @@ struct NGCEXTEventI { 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_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; @@ -269,6 +347,24 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI { 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( const uint32_t group_number, const uint32_t peer_number,