commit c9479153892ff3aee0e65d33cc61aff8df6aa7bc Author: Green Sky Date: Thu Jan 12 19:59:15 2023 +0100 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..69f2c1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Erik Scholz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d6a5334 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# NGC custom packet multiplexer + +uses a single leading byte in custom packets to determain which callback to call + +`ngc_ext.h` is the public c interface + +## TODO: + +- make c only + - merge .hpp into .h + - move .cpp to .c +- public/private packet + diff --git a/ngc_ext.cpp b/ngc_ext.cpp new file mode 100644 index 0000000..11a12fd --- /dev/null +++ b/ngc_ext.cpp @@ -0,0 +1,106 @@ +#include "./ngc_ext.hpp" + +//#include +#include + +using namespace NGC_EXT; + +// global scope + +NGC_EXT_CTX* NGC_EXT_new(void) { + auto* ctx = new NGC_EXT_CTX; + // TODO: this is likely not necessary + for (auto& it : ctx->callbacks) { + it = nullptr; + } + for (auto& it : ctx->user_data) { + it = nullptr; + } + return ctx; +} + +void NGC_EXT_kill(NGC_EXT_CTX* ngc_ext_ctx) { + delete ngc_ext_ctx; +} + +#define _EXT_HAVE(x, error) if ((length - curser) < (x)) { error; } +void NGC_EXT_handle_group_custom_packet( + Tox* tox, + NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + uint32_t peer_number, + + const uint8_t* data, + size_t length + //void *user_data +) { + size_t curser = 0; + + _EXT_HAVE(1, return) + + PacketType pkg_type = static_cast(*(data + curser)); + curser++; + + fprintf(stderr, "EX: custom_packet [%s] %lu\n", pkgid2str(pkg_type), length); + + if (pkg_type == INVALID) { + fprintf(stderr, "(invalid)\n"); + return; + } + + auto handle_fn = ngc_ext_ctx->callbacks[pkg_type]; + auto handle_ud = ngc_ext_ctx->user_data[pkg_type]; // can be null + if (handle_fn == nullptr) { + fprintf(stderr, "EX: !!! no handler for packet\n"); + return; + } + + handle_fn(tox, ngc_ext_ctx, group_number, peer_number, data+curser, length-curser, handle_ud); +} +#undef _EXT_HAVE + +namespace NGC_EXT { + +bool GroupKey::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 GroupKey::operator==(const GroupKey& rhs) const { + for (size_t i = 0; i < data.size(); i++) { + if (data[i] != rhs.data[i]) { + return false; + } + } + return true; +} + +bool PeerKey::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 PeerKey::operator==(const PeerKey& rhs) const { + for (size_t i = 0; i < data.size(); i++) { + if (data[i] != rhs.data[i]) { + return false; + } + } + return true; +} + +} // NGC_EXT + diff --git a/ngc_ext.h b/ngc_ext.h new file mode 100644 index 0000000..6887066 --- /dev/null +++ b/ngc_ext.h @@ -0,0 +1,42 @@ +#ifndef C_NGC_EXT_H +#define C_NGC_EXT_H + +// this is a c header + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// copy from tox.h: +#ifndef TOX_DEFINED +#define TOX_DEFINED +typedef struct Tox Tox; +#endif /* TOX_DEFINED */ + +typedef struct NGC_EXT_CTX NGC_EXT_CTX; + +NGC_EXT_CTX* NGC_EXT_new(void); +void NGC_EXT_kill(NGC_EXT_CTX* ngc_ext_ctx); + +void NGC_EXT_handle_group_custom_packet( + Tox* tox, + NGC_EXT_CTX* ngc_ext_ctx, + + uint32_t group_number, + uint32_t peer_number, + + // bool private, + + const uint8_t *data, + size_t length + //void *user_data +); + +#ifdef __cplusplus +} +#endif + +#endif // C_NGC_EXT_H + diff --git a/ngc_ext.hpp b/ngc_ext.hpp new file mode 100644 index 0000000..c565845 --- /dev/null +++ b/ngc_ext.hpp @@ -0,0 +1,132 @@ +#pragma once + +#include + +#include "ngc_ext.h" + +#include + +// public scope + +using handle_group_custom_packet_cb = void(*)( + Tox* tox, + NGC_EXT_CTX* ngc_ext_ctx, // TODO: useless? + + uint32_t group_number, + uint32_t peer_number, + + const uint8_t* data, + size_t length, + void* user_data +); + +struct NGC_EXT_CTX { + std::array callbacks; + std::array user_data; +}; + +namespace NGC_EXT { + +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 = 1u, + + // 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 = 8u, + + // TODO: request result negative, speed up not found + + // 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) + // - 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) + // - X bytes (file_kind dependent id, differnt sizes) + FT1_INIT, + + // acknowlage init (like an accept) + // like tox ft control continue + // - 1 byte (transfer_id) + FT1_INIT_ACK, + + // TODO: init deny, speed up non acceptance + + // 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 + // - 1 byte (temporary_file_tf_id) + // // this is implicit (pkg size)- 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, +}; + +// TODO: using alias would be fine +struct GroupKey { + std::array data; + + GroupKey(void) = default; + GroupKey(const GroupKey& other) : data(other.data) {} + GroupKey(GroupKey&&) = delete; + GroupKey& operator=(const GroupKey& other) { data = other.data; return *this; } + bool operator<(const GroupKey& rhs) const; + bool operator==(const GroupKey& rhs) const; + size_t size(void) const { return data.size(); } +}; + +struct PeerKey { + std::array data; + + PeerKey(void) = default; + PeerKey(const PeerKey& other) : data(other.data) {} + PeerKey(PeerKey&&) = delete; + PeerKey& operator=(const PeerKey& other) { data = other.data; return *this; } + bool operator<(const PeerKey& rhs) const; + bool operator==(const PeerKey& rhs) const; + size_t size(void) const { return data.size(); } +}; + +[[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) + + default: return ""; + } +#undef _EXT_CASE +} + +} // NGC_EXT +