diff --git a/solanaceae/ngc_ext/ngcext.cpp b/solanaceae/ngc_ext/ngcext.cpp index 55e2044..8fc6064 100644 --- a/solanaceae/ngc_ext/ngcext.cpp +++ b/solanaceae/ngc_ext/ngcext.cpp @@ -123,6 +123,83 @@ bool NGCEXTEventProvider::parse_ft1_init_ack( ); } +bool NGCEXTEventProvider::parse_ft1_init_ack_v2( + uint32_t group_number, uint32_t peer_number, + const uint8_t* data, size_t data_size, + bool _private +) { + if (!_private) { + std::cerr << "NGCEXT: ft1_init_ack_v2 cant be public\n"; + return false; + } + + Events::NGCEXT_ft1_init_ack e; + e.group_number = group_number; + e.peer_number = peer_number; + size_t curser = 0; + + // - 1 byte (temporary_file_tf_id) + _DATA_HAVE(sizeof(e.transfer_id), std::cerr << "NGCEXT: packet too small, missing transfer_id\n"; return false) + e.transfer_id = data[curser++]; + + // - 2 byte (max_lossy_data_size) + if ((data_size - curser) >= sizeof(e.max_lossy_data_size)) { + e.max_lossy_data_size = 0; + for (size_t i = 0; i < sizeof(e.max_lossy_data_size); i++, curser++) { + e.max_lossy_data_size |= uint16_t(data[curser]) << (i*8); + } + } else { + e.max_lossy_data_size = 500-4; // default + } + + return dispatch( + NGCEXT_Event::FT1_INIT_ACK, + e + ); +} + +bool NGCEXTEventProvider::parse_ft1_init_ack_v3( + uint32_t group_number, uint32_t peer_number, + const uint8_t* data, size_t data_size, + bool _private +) { + if (!_private) { + std::cerr << "NGCEXT: ft1_init_ack_v3 cant be public\n"; + return false; + } + + Events::NGCEXT_ft1_init_ack e; + e.group_number = group_number; + e.peer_number = peer_number; + size_t curser = 0; + + // - 1 byte (temporary_file_tf_id) + _DATA_HAVE(sizeof(e.transfer_id), std::cerr << "NGCEXT: packet too small, missing transfer_id\n"; return false) + e.transfer_id = data[curser++]; + + // - 2 byte (max_lossy_data_size) + if ((data_size - curser) >= sizeof(e.max_lossy_data_size)) { + e.max_lossy_data_size = 0; + for (size_t i = 0; i < sizeof(e.max_lossy_data_size); i++, curser++) { + e.max_lossy_data_size |= uint16_t(data[curser]) << (i*8); + } + } else { + e.max_lossy_data_size = 500-4; // default + } + + // - 1 byte (feature_flags) + if ((data_size - curser) >= sizeof(e.feature_flags)) { + e.feature_flags = data[curser++]; + } else { + e.feature_flags = 0x00; // default + } + + return dispatch( + NGCEXT_Event::FT1_INIT_ACK, + e + ); +} + bool NGCEXTEventProvider::parse_ft1_data( uint32_t group_number, uint32_t peer_number, const uint8_t* data, size_t data_size, @@ -229,41 +306,6 @@ bool NGCEXTEventProvider::parse_ft1_message( ); } -bool NGCEXTEventProvider::parse_ft1_init_ack_v2( - uint32_t group_number, uint32_t peer_number, - const uint8_t* data, size_t data_size, - bool _private -) { - if (!_private) { - std::cerr << "NGCEXT: ft1_init_ack_v2 cant be public\n"; - return false; - } - - Events::NGCEXT_ft1_init_ack e; - e.group_number = group_number; - e.peer_number = peer_number; - size_t curser = 0; - - // - 1 byte (temporary_file_tf_id) - _DATA_HAVE(sizeof(e.transfer_id), std::cerr << "NGCEXT: packet too small, missing transfer_id\n"; return false) - e.transfer_id = data[curser++]; - - // - 2 byte (max_lossy_data_size) - if ((data_size - curser) >= sizeof(e.max_lossy_data_size)) { - e.max_lossy_data_size = 0; - for (size_t i = 0; i < sizeof(e.max_lossy_data_size); i++, curser++) { - e.max_lossy_data_size |= uint16_t(data[curser]) << (i*8); - } - } else { - e.max_lossy_data_size = 500-4; // default - } - - return dispatch( - NGCEXT_Event::FT1_INIT_ACK, - e - ); -} - bool NGCEXTEventProvider::parse_ft1_have( uint32_t group_number, uint32_t peer_number, const uint8_t* data, size_t data_size, @@ -401,6 +443,52 @@ bool NGCEXTEventProvider::parse_ft1_have_all( ); } +bool NGCEXTEventProvider::parse_ft1_init2( + uint32_t group_number, uint32_t peer_number, + const uint8_t* data, size_t data_size, + bool _private +) { + if (!_private) { + std::cerr << "NGCEXT: ft1_init2 cant be public\n"; + return false; + } + + Events::NGCEXT_ft1_init2 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); + } + + // - 8 bytes (data size) + e.file_size = 0u; + _DATA_HAVE(sizeof(e.file_size), std::cerr << "NGCEXT: packet too small, missing file_size\n"; return false) + for (size_t i = 0; i < sizeof(e.file_size); i++, curser++) { + e.file_size |= uint64_t(data[curser]) << (i*8); + } + + // - 1 byte (temporary_file_tf_id) + _DATA_HAVE(sizeof(e.transfer_id), std::cerr << "NGCEXT: packet too small, missing transfer_id\n"; return false) + e.transfer_id = data[curser++]; + + // - 1 byte feature flags + _DATA_HAVE(sizeof(e.feature_flags), std::cerr << "NGCEXT: packet too small, missing feature_flags\n"; return false) + e.feature_flags = data[curser++]; + + // - X bytes (file_kind dependent id, differnt sizes) + e.file_id = {data+curser, data+curser+(data_size-curser)}; + + return dispatch( + NGCEXT_Event::FT1_INIT2, + e + ); +} + bool NGCEXTEventProvider::parse_pc1_announce( uint32_t group_number, uint32_t peer_number, const uint8_t* data, size_t data_size, @@ -445,7 +533,8 @@ bool NGCEXTEventProvider::handlePacket( return parse_ft1_init(group_number, peer_number, data+1, data_size-1, _private); case NGCEXT_Event::FT1_INIT_ACK: //return parse_ft1_init_ack(group_number, peer_number, data+1, data_size-1, _private); - return parse_ft1_init_ack_v2(group_number, peer_number, data+1, data_size-1, _private); + //return parse_ft1_init_ack_v2(group_number, peer_number, data+1, data_size-1, _private); + return parse_ft1_init_ack_v3(group_number, peer_number, data+1, data_size-1, _private); case NGCEXT_Event::FT1_DATA: return parse_ft1_data(group_number, peer_number, data+1, data_size-1, _private); case NGCEXT_Event::FT1_DATA_ACK: @@ -458,6 +547,8 @@ bool NGCEXTEventProvider::handlePacket( return parse_ft1_bitset(group_number, peer_number, data+1, data_size-1, _private); case NGCEXT_Event::FT1_HAVE_ALL: return parse_ft1_have_all(group_number, peer_number, data+1, data_size-1, _private); + case NGCEXT_Event::FT1_INIT2: + return parse_ft1_init2(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: @@ -701,6 +792,39 @@ bool NGCEXTEventProvider::send_ft1_have_all( return _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, pkg) == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK; } +bool NGCEXTEventProvider::send_ft1_init2( + uint32_t group_number, uint32_t peer_number, + uint32_t file_kind, + uint64_t file_size, + uint8_t transfer_id, + uint8_t feature_flags, + 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) + // - 1 byte (feature_flags) + // - X bytes (file_kind dependent id, differnt sizes) + + std::vector pkg; + pkg.push_back(static_cast(NGCEXT_Event::FT1_INIT2)); + 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); + pkg.push_back(feature_flags); + 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; +} + static std::vector build_pc1_announce(const uint8_t* id_data, size_t id_size) { // - 1 byte packet id // - X bytes (id, differnt sizes) diff --git a/solanaceae/ngc_ext/ngcext.hpp b/solanaceae/ngc_ext/ngcext.hpp index aafc3fb..46d0ac0 100644 --- a/solanaceae/ngc_ext/ngcext.hpp +++ b/solanaceae/ngc_ext/ngcext.hpp @@ -56,6 +56,7 @@ namespace Events { std::vector file_id; }; + // DEPRECATED: use FT1_INIT2 instead struct NGCEXT_ft1_init { uint32_t group_number; uint32_t peer_number; @@ -84,6 +85,11 @@ namespace Events { // - 2 byte (self_max_lossy_data_size) uint16_t max_lossy_data_size; + + // - 1 byte feature flags + // - 0x01 advertised zstd compression + // - 0x02 + uint8_t feature_flags; }; struct NGCEXT_ft1_data { @@ -176,6 +182,30 @@ namespace Events { std::vector file_id; }; + struct NGCEXT_ft1_init2 { + uint32_t group_number; + uint32_t peer_number; + + // tell the other side you want to start a FT + + // - 4 byte (file_kind) + uint32_t file_kind; + + // - 8 bytes (data size) + uint64_t file_size; + + // - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts) + uint8_t transfer_id; + + // - 1 byte feature flags + // - 0x01 advertise zstd compression + // - 0x02 + uint8_t feature_flags; + + // - X bytes (file_kind dependent id, differnt sizes) + std::vector file_id; + }; + struct NGCEXT_pc1_announce { uint32_t group_number; uint32_t peer_number; @@ -210,6 +240,7 @@ enum class NGCEXT_Event : uint8_t { // 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 + // DEPRECATED: use FT1_INIT2 instead // - 4 byte (file_kind) // - 8 bytes (data size, can be 0 if unknown, BUT files have to be atleast 1 byte) // - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts) @@ -219,7 +250,8 @@ enum class NGCEXT_Event : uint8_t { // acknowlage init (like an accept) // like tox ft control continue // - 1 byte (transfer_id) - // - 2 byte (self_max_lossy_data_size) (optional since v2) + // - 2 byte (self_max_lossy_data_size) (optimal since v2) + // - 1 byte feature flags (optimal since v3, requires prev) FT1_INIT_ACK, // TODO: init deny, speed up non acceptance @@ -277,8 +309,18 @@ enum class NGCEXT_Event : uint8_t { // - X bytes (file_kind dependent id, differnt sizes) FT1_HAVE_ALL, + // tell the other side you want to start a FT + // update: added feature flags (compression) + // - 4 byte (file_kind) + // - 8 bytes (data size, can be 0 if unknown, BUT files have to be atleast 1 byte) + // - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts) + // - 1 byte feature flags + // - X bytes (file_kind dependent id, differnt sizes) + FT1_INIT2, + // TODO: FT1_IDONTHAVE, tell a peer you no longer have said chunk // TODO: FT1_REJECT, tell a peer you wont fulfil the request + // TODO: FT1_CANCEL, tell a peer you stop the transfer // 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 @@ -306,6 +348,7 @@ struct NGCEXTEventI { 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_ft1_have_all&) { return false; } + virtual bool onEvent(const Events::NGCEXT_ft1_init2&) { return false; } virtual bool onEvent(const Events::NGCEXT_pc1_announce&) { return false; } }; @@ -350,6 +393,18 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI { bool _private ); + bool parse_ft1_init_ack_v2( + uint32_t group_number, uint32_t peer_number, + const uint8_t* data, size_t data_size, + bool _private + ); + + bool parse_ft1_init_ack_v3( + uint32_t group_number, uint32_t peer_number, + const uint8_t* data, size_t data_size, + bool _private + ); + bool parse_ft1_data( uint32_t group_number, uint32_t peer_number, const uint8_t* data, size_t data_size, @@ -368,12 +423,6 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI { bool _private ); - bool parse_ft1_init_ack_v2( - uint32_t group_number, uint32_t peer_number, - const uint8_t* data, size_t data_size, - bool _private - ); - bool parse_ft1_have( uint32_t group_number, uint32_t peer_number, const uint8_t* data, size_t data_size, @@ -392,6 +441,12 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI { bool _private ); + bool parse_ft1_init2( + 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, @@ -468,6 +523,15 @@ class NGCEXTEventProvider : public ToxEventI, public NGCEXTEventProviderI { const uint8_t* file_id, size_t file_id_size ); + bool send_ft1_init2( + uint32_t group_number, uint32_t peer_number, + uint32_t file_kind, + uint64_t file_size, + uint8_t transfer_id, + uint8_t feature_flags, + const uint8_t* file_id, size_t file_id_size + ); + bool send_pc1_announce( uint32_t group_number, uint32_t peer_number, const uint8_t* id_data, size_t id_size