diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be9f38c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +src/.old +src/test.cpp +libstadium.so +libstadiumtest_release +libstadiumtest_sanitizer +libstadiumtest_fortified \ No newline at end of file diff --git a/Makefile b/Makefile index 18a14e7..4907b42 100644 --- a/Makefile +++ b/Makefile @@ -2,16 +2,21 @@ CC = g++ CFLAGS_DEFAULT = -march=native -std=c++23 -CFLAGS_DEBUG = -Wall -Werror -Wno-uninitialized -Wno-analyzer-use-of-uninitialized-value -fanalyzer -ggdb -CFLAGS_DEBUG_S = -O0 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow +CFLAGS_DEBUG = -ggdb -Wall -Werror -Wno-reorder -Wno-uninitialized -fanalyzer -Wno-analyzer-use-of-uninitialized-value +#CFLAGS_DEBUG_S = -O0 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow CFLAGS_DEBUG_F = -O1 -D_FORTIFY_SOURCE=3 CFLAGS_RELEASE = -static-libgcc -static-libstdc++ -static -Ofast -fdevirtualize-speculatively -fdata-sections -ffunction-sections -Wl,-gc-sections -Wl,-strip-all -Wl,-strip-discarded -flto -s -D_FORTIFY_SOURCE=3 -SOURCES = src/stadium.hpp src/stadium.cpp src/kldr.hpp +SOURCES = src/Stadium.hpp src/Stadium.cpp \ + src/Event.hpp src/Event.cpp \ + src/Worker.hpp src/Worker.cpp \ + src/KLDR.hpp \ + src/Utils.hpp SOURCES_TEST = src/test.cpp #LINKED_LIBS = -l OUTPUT_LIB = libstadium.so -OUTPUT_TEST_BIN_S = libstadiumtest_sanitizer +OUTPUT_TEST_BIN = libstadiumtest_release +#OUTPUT_TEST_BIN_S = libstadiumtest_sanitizer OUTPUT_TEST_BIN_F = libstadiumtest_fortified @@ -19,9 +24,7 @@ default: clean release_test debug_test: $(SOURCES) $(SOURCES_TEST) - $(CC) $(CFLAGS_DEFAULT) $(CFLAGS_DEBUG) $(CFLAGS_DEBUG_S) $(SOURCES) $(SOURCES_TEST) -o $(OUTPUT_TEST_BIN_S) $(CC) $(CFLAGS_DEFAULT) $(CFLAGS_DEBUG) $(CFLAGS_DEBUG_F) $(SOURCES) $(SOURCES_TEST) -o $(OUTPUT_TEST_BIN_F) - #$(LINKED_LIBS) debug: $(SOURCES) echo "NYI" @@ -34,4 +37,4 @@ release: $(SOURCES) clean: - rm -f $(OUTPUT_LIB) $(OUTPUT_TEST_BIN_S) $(OUTPUT_TEST_BIN_F) \ No newline at end of file + rm -f $(OUTPUT_LIB) $(OUTPUT_TEST_BIN_F) $(OUTPUT_TEST_BIN) \ No newline at end of file diff --git a/README.md b/README.md index 048712e..8679167 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,4 @@ _Эталонная имплементация библиотеки с реализацией протокола Stadium на языке C++._ -**В процессе активной разработки!/Under active development!** - - -## Пространства имён - -`Stadium::Base`: базовые инструменты, не подлежащие принципиальному изменению в будущем. -`Stadium::v1`: то, что может быть изменено в последующих версиях. \ No newline at end of file +**В процессе активной разработки!/Under active development!** \ No newline at end of file diff --git a/src/Event.cpp b/src/Event.cpp new file mode 100644 index 0000000..b5dcc01 --- /dev/null +++ b/src/Event.cpp @@ -0,0 +1,53 @@ +/* + * Event.cpp + * Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms. + * + */ + +#include "Event.hpp" + + + +namespace Stadium::v1 { + + + +// Default ctor +Event::Event () { + this->Type.Category = this->Type.Subcategory = this->AsyncID = 0; +} + +// Ctor with parsing of raw char array +Event::Event (const char* data, size_t data_sz) { + // TODO +} + +// Ctor with positional arguments +Event::Event (EventType type, KLDRArray<> data, uint16_t id = 0) : Type(std::move(type)), Payload(std::move(data)), AsyncID(id) { + // TODO: calculate hash +} + +// Ctor with positional arguments number two +Event::Event (uint8_t cat, uint8_t subcat, KLDRArray<> data, uint16_t id = 0) : Payload(std::move(data)), AsyncID(id) { + this->Type.Category = cat; + this->Type.Subcategory = subcat; + // TODO: calculate hash +} + +// Write to stdout info about event +void +Event::Print () { + printf( + "[Event] Object at: %lu; Category: 0x%.2hhx; Subcategory: 0x%.2hhx; AsyncID: %hu; Payload size: cells: %lu, bytes:%lu\n", // TODO: add hash + reinterpret_cast(this), + this->Type.Category, + this->Type.Subcategory, + this->AsyncID, + this->Payload.CellsAmount(), + this->Payload.FlatSize() + ); +} + + + +} \ No newline at end of file diff --git a/src/Event.hpp b/src/Event.hpp index ed83261..628e023 100644 --- a/src/Event.hpp +++ b/src/Event.hpp @@ -9,25 +9,49 @@ +#include +#include #include "KLDR.hpp" -namespace Stadium { -namespace v1 { +namespace Stadium::v1 { -class Event { - public: - struct { - uint8_t Category; - uint8_t Subcategory; - } Type; // ??? - uint32_t ServerSession; - // TODO: payload hash - Base::KLDRArray<> Payload; + + +// Asynchronous ID of event +typedef uint16_t EventAsyncID; + +// Type of event +struct EventType { + uint8_t Category; + uint8_t Subcategory; }; -} +// Event class +class Event { + public: + uint32_t Lifetime = 0; // Lifetime of event in seconds + + private: + // These are the "physical" members that will be packed to binary + std::vector Hash; + // CryptoAlgo HashAlgo; // TODO + KLDRArray<> Payload; + + public: + EventType Type; + EventAsyncID AsyncID; + + Event (); + Event (const char*, size_t); + Event (EventType, KLDRArray<>, uint16_t); + Event (uint8_t, uint8_t, KLDRArray<>, uint16_t); + void Print (); +}; + + + } diff --git a/src/EventQueue.hpp b/src/EventQueue.hpp deleted file mode 100644 index fde18c1..0000000 --- a/src/EventQueue.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * EventQueue.hpp - * Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms. - * - */ - -#ifndef LIBSTADIUM_EVENTQUEUE_HPP -#define LIBSTADIUM_EVENTQUEUE_HPP - - - -#include -#include "Event.hpp" - - - -namespace Stadium { -namespace v1 { - -class EventQueue { - protected: - std::vector Array; - - public: - //void Add (Event); - //Event Get (); -}; - -} -} - - - -#endif \ No newline at end of file diff --git a/src/KLDR.hpp b/src/KLDR.hpp index 395ffa5..6137605 100644 --- a/src/KLDR.hpp +++ b/src/KLDR.hpp @@ -17,34 +17,33 @@ -namespace Stadium { +namespace Stadium::v1 { + -namespace v1 { enum KLDRDefaultKeys : uint8_t { - Data = 0x01, - ObjectID = 0x02, - SrcEventAuthor = 0x03, - PrevEvent = 0x04, - NextEvent = 0x05, - BatchNumber = 0x06, - Path = 0x07, - Power = 0x08, + Data = 0x01, // Main data of event + ObjectID = 0x02, // ID of object in local context + SrcEventAuthor = 0x03, // Source author of event + PrevEvent = 0x04, // ID of previous event, logically connected to this + NextEvent = 0x05, // ID of next event + BatchNumber = 0x06, // Number of event in chain of events + Path = 0x07, // Path to requested/uploaded resource + Power = 0x08, // Access right to object + ServerSession = 0x09, // ID of server-side session // Crypto-related - CryptoAlgos = 0x11, - CryptoKeyID = 0x12, - SignedDataHash = 0x13 + CryptoAlgos = 0x11, // Array of used cryptography algos + CryptoKeyID = 0x12, // ID of crypto key used for data encryption in this event + SignedDataHash = 0x13 // Signed by sender hash of data }; -} -namespace Base { /* - * KLDR stands for "Key-Length-Data-Repeat" + * KLDR stands for "Key-Length-Data-Repeat". * Schematically, binary array with KLDR-formatted data looks like this. * Single cell: - * [key: 1/2 bytes][length of data: 1/2/4 bytes][data: bytes] + * [key: 1 or 2 bytes][length of data: 1/2/4 bytes][data: bytes] * Whole array: * [cell 1][cell 2]...[cell n] * @@ -54,22 +53,64 @@ namespace Base { */ template class KLDRArray { - protected: + private: std::vector Keys; std::vector Lengths; - std::vector Values; + std::vector Values; public: - //KLDRArray (); // TODO: check used types and/or parse given char array/vector + // Constructor + KLDRArray () {}; // TODO: check used types and/or parse given char array/vector // Destructor ~KLDRArray () { // Freeing all pointers if vector is not empty - for (size_t i = 0; i < this->Keys.size(); i++) { - operator delete(this->Values[i]); + for (size_t i = 0; i < this->CellsAmount(); i++) { + delete[] this->Values[i]; } } + // Move operator WARNING: есть шанс, что я тут сделал ложно, ибо мб мув просто продлевает время жизни вместо перемещения. Ассигнмента тоже касается + KLDRArray (KLDRArray&& src) : Keys(std::move(src.Keys)), Lengths(std::move(src.Lengths)), Values(std::move(src.Values)) {} + + // Move assignment operator + KLDRArray& operator= (KLDRArray&& src) { + if (this == &src) + return *this; + + this->Keys = std::move(src.Keys); + this->Lengths = std::move(src.Lengths); + this->Values = std::move(src.Values); + return *this; + } + + // Copy operator (creating deep copy) + KLDRArray (KLDRArray& src) : Keys(src.Keys), Lengths(src.Lengths) + { + size_t valSize = 0; + for (size_t i = 0; i < src.Values.size(); i++) { + valSize = src.Lengths[i]; + this->Values.push_back(new char[valSize]); + std::copy(src.Values[i], src.Values[i] + valSize, this->Values[i]); + } + } + + // Copy assignment operator (creating deep copy) + KLDRArray& operator= (const KLDRArray& src) { + if (this == &src) + return *this; + + this->Keys = src.Keys; + this->Lengths = src.Lengths; + size_t valSize = 0; + for (size_t i = 0; i < src.Values.size(); i++) { + valSize = src.Lengths[i]; + this->Values.push_back(new char[valSize]); + std::copy(src.Values[i], src.Values[i] + valSize, this->Values[i]); + } + return *this; + } + // Write data to PREALLOCATED char array // WARNING: unsafe and probably UB (may be i test this later but who knows) void AsArrayF (char* arr) { @@ -79,13 +120,13 @@ class KLDRArray { ptr += sizeof(KeyT); std::copy((char*)&this->Lengths[i], (char*)(&this->Lengths[i] + sizeof(LengthT)), ptr); ptr += sizeof(LengthT); - std::copy((char*)this->Values[i], ((char*)this->Values[i]) + this->Lengths[i], ptr); + std::copy(this->Values[i], this->Values[i] + this->Lengths[i], ptr); ptr += this->Lengths[i]; } } // Return contents as char vector - std::vector AsArray () { + std::vector AsArray () const { std::vector result; for (size_t i = 0; i < this->CellsAmount(); i++) { for (uint j = 0; j < sizeof(KeyT); j++) @@ -99,49 +140,61 @@ class KLDRArray { } // Print all contents of array to stdout - void Print () { - printf("Elements amount: %lu\n", this->CellsAmount()); + void Print () const { + printf( + "[KLDRArray] Object at: %lu; " + "KeyT size: %lu; " + "LengthT size: %lu; " + "Elements amount: %lu\n", + (size_t)this, + sizeof(KeyT), + sizeof(LengthT), + this->CellsAmount() + ); for (size_t i = 0; i < this->CellsAmount(); i++) { - printf("Key: "); + printf("\tKey: "); switch (this->Keys[i]) { - case KLDRDefaultKeys::Data: + case v1::KLDRDefaultKeys::Data: printf("Data"); break; - case KLDRDefaultKeys::ObjectID: + case v1::KLDRDefaultKeys::ObjectID: printf("ObjectID"); break; - case KLDRDefaultKeys::SrcEventAuthor: + case v1::KLDRDefaultKeys::SrcEventAuthor: printf("SrcEventAuthor"); break; - case KLDRDefaultKeys::PrevEvent: + case v1::KLDRDefaultKeys::PrevEvent: printf("PrevEvent"); break; - case KLDRDefaultKeys::NextEvent: + case v1::KLDRDefaultKeys::NextEvent: printf("NextEvent"); break; - case KLDRDefaultKeys::BatchNumber: + case v1::KLDRDefaultKeys::BatchNumber: printf("BatchNumber"); break; - case KLDRDefaultKeys::Path: + case v1::KLDRDefaultKeys::Path: printf("Path"); break; - case KLDRDefaultKeys::Power: + case v1::KLDRDefaultKeys::Power: printf("Power"); break; - case KLDRDefaultKeys::CryptoAlgos: + case v1::KLDRDefaultKeys::ServerSession: + printf("ServerSession"); + break; + case v1::KLDRDefaultKeys::CryptoAlgos: printf("CryptoAlgos"); break; - case KLDRDefaultKeys::CryptoKeyID: + case v1::KLDRDefaultKeys::CryptoKeyID: printf("CryptoKeyID"); break; - case KLDRDefaultKeys::SignedDataHash: + case v1::KLDRDefaultKeys::SignedDataHash: printf("SignedDataHash"); break; default: printf("0x%.2X", (KeyT)this->Keys[i]); } - printf("; Length: %u; ", (LengthT)this->Lengths[i]); - printf("Value: "); + printf("; Length: %u; ", (uint)this->Lengths[i]); + printf("ValuePtr: %lu; Value: ", (uint64_t)this->Values[i]); for (LengthT j = 0; j < this->Lengths[i]; j++) printf("%.2X ", ((uint8_t*)this->Values[i])[j]); printf("\n"); @@ -149,12 +202,12 @@ class KLDRArray { } // Get amount of cells in array - inline size_t CellsAmount () { + inline size_t CellsAmount () const { return this->Keys.size(); } // Get size of all data in array as if they in packed condition - size_t FlatSize () { + size_t FlatSize () const { size_t result = this->Keys.size() * sizeof(KeyT) + this->Lengths.size() * sizeof(LengthT); for (size_t i = 0; i < this->CellsAmount(); i++) result += this->Lengths[i]; @@ -162,7 +215,7 @@ class KLDRArray { } // If there are specified key - bool KeyExists (KeyT key) { + bool KeyExists (KeyT key) const { for (size_t i = 0; i < this->CellsAmount(); i++) { if (this->Keys[i] == key) { return true; @@ -171,25 +224,24 @@ class KLDRArray { return false; } - // Add new cell to array, fast version without key checks - void AddF (KeyT key, LengthT length, void* data) { + // Add new cell to array, fast version without key checks, data will be copied + void AddF (KeyT key, LengthT length, char* data) { this->Keys.push_back(key); this->Lengths.push_back(length); - void* newData = operator new(length); // Yes, allocating memory for void pointer really looks like this - std::copy((char*)data, (char*)data + length, (char*)newData); // Dirty hacks, YES! + char* newData = new char[length]; + std::copy(data, data + length, newData); this->Values.push_back(newData); - // NOTICE: there is `std::is_pod()`, so may be we can use one more template to make this a little more safe (may be) } // Add new cell to array, but only if key is unique - void Add (KeyT key, LengthT length, void* data) { + void Add (KeyT key, LengthT length, char* data) { if (this->KeyExists(key)) throw std::invalid_argument("supplied key already exist"); this->AddF(key, length, data); } // Get just pointer to value from array by key - void* Get (KeyT key) { + char* Get (KeyT key) const { for (size_t i = 0; i < this->CellsAmount(); i++) { if (this->Keys[i] == key) { return this->Values[i]; @@ -199,7 +251,7 @@ class KLDRArray { } // Get pointer to value and length from array by key - void* Get (KeyT key, LengthT* length) { + char* Get (KeyT key, LengthT* length) const { for (size_t i = 0; i < this->CellsAmount(); i++) { if (this->Keys[i] == key) { *length = this->Lengths[i]; @@ -209,6 +261,8 @@ class KLDRArray { throw std::invalid_argument("invalid KLDRArray key"); } + // TODO: get copy of value + // Delete cell from array by key void Del (KeyT key) { for (size_t i = 0; i < this->CellsAmount(); i++) { @@ -240,7 +294,7 @@ class KLDRArray { } }; -} + } diff --git a/src/Stadium.cpp b/src/Stadium.cpp index 7c7efd1..f4530e7 100644 --- a/src/Stadium.cpp +++ b/src/Stadium.cpp @@ -2,13 +2,24 @@ * Stadium.cpp * Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms. * - * -> [ Incoming Events Queue ] --> [ Base Event Handlers ] - * / \-> [ Custom Event Handlers ] - * [ Transport ] <-> [ StadiumCrypto (optional) ] <- -> [ Expected Event Handlers ] - * \ - * <- [ Outcoming Events Queue ] <--- [ Base Methods ] + * API logic: + * + * -> [ Incoming Events Queue ] ---> [ Base Event Handlers ] + * / \-> [ Custom Event Handlers ] + * [ Transport ] <-> [ StadiumCrypto (optional) ] <-> -> [ Expected Event Handlers ] + * \ + * <- [ Outcoming Events Queue ] <--- [ Base Methods ] * \ * <- [ Custom Methods ] + * + * Arch logic: + * + * [ Base Event Handlers ] [ Custom Event Handlers ] [ Base Methods ] [ Custom Methods ] + * [ Base Event Management ] [ E2EE ] [ Far-Visibility Integrity Checks ] [ DoS Protection ] + * [ Session Management ] [ Direct-Visibility Integrity Checks ] [ DoS Protection ] + * [ Several Workers ] [ Event Parser ] [ DoS Protection ] + * [ Various Transport Adapters ] + * */ #include "Stadium.hpp" diff --git a/src/Stadium.hpp b/src/Stadium.hpp index 45dcf93..7050a35 100644 --- a/src/Stadium.hpp +++ b/src/Stadium.hpp @@ -9,17 +9,19 @@ -#include "EventQueue.hpp" +#include "Utils.hpp" +#include "KLDR.hpp" +#include "Event.hpp" +#include "Worker.hpp" -namespace Stadium { -namespace v1 { +namespace Stadium::v1 { // TODO +// __DATE__ __TIME__ } -} diff --git a/src/Utils.hpp b/src/Utils.hpp index bdd5cfe..cc2bfcb 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -10,28 +10,29 @@ #include -#include +#include -namespace Stadium { -namespace Utils { +namespace Stadium::Utils { -void PrintArray (std::vector arr) { - printf("Length: %lu\n", arr.size()); + + +// Print information about any std-compatible container to stdout +template +void +PrintArray (Container& arr) { + printf("Array at %lu; length: %lu\n", + reinterpret_cast(&arr), + arr.size() + ); for (size_t i = 0; i < arr.size(); i++) printf("%.2X ", (uint8_t)arr[i]); printf("\n"); } -void PrintArray (char* arr, size_t len) { - printf("Length: %lu\n", len); - for (size_t i = 0; i < len; i++) - printf("%.2X ", (uint8_t)arr[i]); - printf("\n"); -} -} + } diff --git a/src/Worker.cpp b/src/Worker.cpp new file mode 100644 index 0000000..1a5c617 --- /dev/null +++ b/src/Worker.cpp @@ -0,0 +1,54 @@ +/* + * Worker.cpp + * Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms. + * + */ + +#include "Worker.hpp" + + + +namespace Stadium::v1 { + + + +// Create event from raw bytes (ATTENTION: maybe move this method to Event class) +Event +Worker::ParseRawData (const char* data) { + // TODO + return Event{}; +} + +// Parse ingoing packet data to event, check its properties and put it to queue if all okay +void +Worker::PutIngoing (const char* data) { + // TODO +} + +// Send outgoing event (NOTICE: maybe rework) +void +Worker::PutOutgoing (EventType type, KLDRArray<> data) { + // TODO +} + +// Bind handler for ingoing events +void +Worker::BindHandler (EventType, void()) { + // TODO +} + +// Start ingoing event processing loop +void +Worker::IngoingLoop () { + // TODO +} + +// Get single outgoing event from queue and form it to binary +std::vector +Worker::GetOutgoingDataVec () { + return std::vector{}; // TODO: remove +} + + + +} \ No newline at end of file diff --git a/src/Worker.hpp b/src/Worker.hpp new file mode 100644 index 0000000..bddc448 --- /dev/null +++ b/src/Worker.hpp @@ -0,0 +1,52 @@ +/* + * Worker.hpp + * Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms. + * + */ + +#ifndef LIBSTADIUM_WORKER_HPP +#define LIBSTADIUM_WORKER_HPP + + + +#include +#include +#include + +#include "KLDR.hpp" +#include "Event.hpp" + + + +namespace Stadium::v1 { + + + +// Working class +class Worker { + private: + static bool Running; // If workers are running + + static std::unordered_map Handlers; // Map of handlers associated with packet types TODO: may be it can be more optimized with reloaded operators + static std::unordered_map ExpectedEvents; // Map of expected events and their async IDs + static std::atomic LastAsyncID; // Increments every use of Expect() + + static std::queue OutgoingEvents; // FIFO of outgoing events + static std::queue IngoingEvents; // FIFO of ingoing events + + public: + Event ParseRawData (const char*); + void PutIngoing (const char*); + void PutOutgoing (EventType, KLDRArray<>); + void BindHandler (EventType, void()); + void IngoingLoop (); + std::vector GetOutgoingDataVec (); +}; + + + +} + + + +#endif \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp index f014ba3..ec6a394 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -4,20 +4,24 @@ int main () { - Stadium::Base::KLDRArray<> arr; + Stadium::v1::KLDRArray<> arr; char str1[] = "goodbye, var?\n"; char str2[] = "hello, world!\n"; char str3[] = "fisting\n"; char str4[] = "IS 300$!!!!!!!!!!!!!!!!!!\n"; char str5[] = "a)\n"; - arr.Add(Stadium::Base::KLDRDefaultKeys::Data, sizeof(str1), (void*)&str1); - arr.Add(Stadium::Base::KLDRDefaultKeys::ObjectID, sizeof(str2), (void*)&str2); - arr.Add(0xF4, sizeof(str3), (void*)&str3); - arr.Add(0x6a, sizeof(str4), (void*)&str4); - arr.Add(Stadium::Base::KLDRDefaultKeys::SignedDataHash, sizeof(str5), (void*)&str5); - std::cout << "Shuffling!" << std::endl; + arr.Add(Stadium::v1::KLDRDefaultKeys::Data, sizeof(str1), (char*)&str1); + arr.Add(Stadium::v1::KLDRDefaultKeys::ObjectID, sizeof(str2), (char*)&str2); + arr.Add(0xF4, sizeof(str3), (char*)&str3); + arr.Add(0x6a, sizeof(str4), (char*)&str4); + arr.Add(Stadium::v1::KLDRDefaultKeys::SignedDataHash, sizeof(str5), (char*)&str5); arr.Shuffle(); arr.Print(); + Stadium::v1::Event e{0x01, 0xf4, std::move(arr), 54}; + e.Print(); + + // + return 0; } \ No newline at end of file