#include #include "ngc_ext_common.h" #include "ngc_hs1.h" #include "ngc_ft1.h" //#include //#include //#include //#include //#include //#include //#include //#include #include struct _GroupKey { std::array data; _GroupKey(void) = default; _GroupKey(const _GroupKey& other) : data(other.data) {} _GroupKey(_GroupKey&&) = delete; bool operator<(const _GroupKey& rhs) const { for (size_t i = 0; i < data.size(); i++) { if (data[i] < rhs.data[i]) { return true; } else if (data[i] > rhs.data[i]) { return false; } } return false; // equal } bool operator==(const _GroupKey& rhs) const { for (size_t i = 0; i < data.size(); i++) { if (data[i] != rhs.data[i]) { return false; } } return true; } }; struct _PeerKey { std::array data; _PeerKey(void) = default; _PeerKey(const _PeerKey& other) : data(other.data) {} _PeerKey(_PeerKey&&) = delete; bool operator<(const _PeerKey& rhs) const { for (size_t i = 0; i < data.size(); i++) { if (data[i] < rhs.data[i]) { return true; } else if (data[i] > rhs.data[i]) { return false; } } return false; // equal } bool operator==(const _PeerKey& rhs) const { for (size_t i = 0; i < data.size(); i++) { if (data[i] != rhs.data[i]) { return false; } } return true; } }; enum _PacketType : uint8_t { // TODO: why? INVALID = 0u, //TODO: make it possible to go further back // 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, // respond to a request with 0 or more message ids, sorted by newest first // - peer_key bytes (the msg_ids are from) // - 1 byte (uint8_t count ids, can be 0) // - array [ // - msg_id bytes (the message id // - ] HS1_RESPONSE_LAST_IDS, // request the other side to initiate a FT // - 1 byte (file_kind) // - X bytes (file_kind dependent id, differnt sizes) FT1_REQUEST, // 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 // - 1 byte (file_kind) // - X bytes (file_kind dependent id, differnt sizes) // - 8 bytes (data size) // TODO: do all file kinds have a size at init? // - 1 byte (temporary_file_tf_id, for this peer only, technically just a prefix to distinguish between simultainious fts) FT1_INIT, // acknowlage init (like an accept) // - 1 byte (temporary_file_tf_id) FT1_INIT_ACK, // data fragment // - 1 byte (temporary_file_tf_id) // - 2 bytes (sequece id) // - X bytes (the data fragment) // (size is implicit) FT1_DATA, // acknowlage data fragments // TODO: last 3 should be sufficient, 5 should be generous, would eleminate the byte for size // - 1 byte (temporary_file_tf_id) // - 1 byte (number of sequence ids to ack, this kind of depends on window size) // - array [ (of sequece ids) // - 2 bytes (sequece id) // - ] FT1_DATA_ACK, // sender has gotten every data fragment acked, so we signal finish // - 1 byte (temporary_file_tf_id) FT1_DATA_FIN, // and we ack that, we need this, so file_id is not reused earlier // - 1 byte (temporary_file_tf_id) 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 } using handle_group_custom_packet_cb = void(*)( Tox* tox, NGC_EXT_CTX* ngc_ext_ctx, uint32_t group_number, uint32_t peer_number, const uint8_t *data, size_t length ); struct NGC_EXT_CTX { std::array callbacks; NGC_HS1* ngc_hs1_ctx = nullptr; NGC_FT1* ngc_ft1_ctx = nullptr; };