libutils, a C++20 utility librarylibutils, une bibliothèque utilitaire C++20
Exceptions, verbose, CLI, arguments, TCP network, processes and shared memory, encryption, custom types and algorithms, in one static library distributed as RPM / DEB packages. The details of every class are in the wiki.Exceptions, verbose, CLI, arguments, réseau TCP, processus et mémoire partagée, chiffrement, types et algorithmes, dans une seule bibliothèque statique distribuée en paquets RPM / DEB. Le détail de chaque classe est dans le wiki.
1. Overview1. Vue d'ensemble
Everything is in the namespace utils::. A project includes only the root header <utils/utils.hpp> and chooses the sections it needs with defines placed before it; nothing defined means everything.Tout est dans le namespace utils::. Un projet inclut seulement l'en-tête racine <utils/utils.hpp> et choisit les sections voulues avec des defines placés avant ; sans define, tout est inclus.
utils.hpp (a group enables its sections, a section its sub-sections).Figure 1 : les defines de utils.hpp (un groupe active ses sections, une section ses sous-sections).| PointPoint | ValueValeur |
|---|---|
| LanguageLangage | C++20, built with clang++ and CMake (>= 3.20)C++20, compilé avec clang++ et CMake (>= 3.20) |
| LibraryBibliothèque | static: libutils.a (optimized), libutils_debug.a, libutils_asan.astatique : libutils.a (optimisée), libutils_debug.a, libutils_asan.a |
| PlatformsPlateformes | Unix (Linux, BSD, macOS) and Windows x86_64 (cross compiled with MinGW-w64), same API (section 7)Unix (Linux, BSD, macOS) et Windows x86_64 (compilation croisée MinGW-w64), même API (section 7) |
| DependencyDépendance | OpenSSL >= 3.0 (encryption, Base64)OpenSSL >= 3.0 (chiffrement, Base64) |
| VersionVersion | utils::version ("v4.1.0"), __LIBUTILS_VERSION__ |
2. Install & integrate2. Installer & intégrer
2.1 Install2.1 Installation
curl -fsSL https://raw.githubusercontent.com/TsukiNi22/libutils/main/setup.sh | bash -s
sudo dnf install libutils
curl -fsSL https://raw.githubusercontent.com/TsukiNi22/libutils/main/setup.sh | bash -s
sudo apt install libutils
git clone https://github.com/TsukiNi22/libutils.git && cd libutils
export BUILD_DIR=build
cmake -S . -B $BUILD_DIR
sudo cmake --build $BUILD_DIR --target install --parallel $(nproc)
sudo dnf install mingw64-libutils # Fedora (requires mingw64-openssl)
sudo apt install mingw64-libutils # Debian / Ubuntu (OpenSSL for MinGW built by hand)
export BUILD_DIR=build-windows
cmake -S . -B $BUILD_DIR -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/mingw-w64.cmake -DCMAKE_BUILD_TYPE=Optimized
cmake --build $BUILD_DIR --parallel $(nproc)
cmake --install $BUILD_DIR --prefix <windows_prefix> # include/, lib/libutils.a, lib/cmake/utils/
cmake --build $BUILD_DIR --target package # mingw64-libutils-* RPM/DEB
| PackagePaquet | ContentContenu |
|---|---|
libutils | libutils-dev + libutils-op |
libutils-dev | headers, CMake configuration (requires openssl-devel / libssl-dev)en-têtes, configuration CMake (nécessite openssl-devel / libssl-dev) |
libutils-op / -db / -as | optimized / debug / asan library (+ libutils-dev-op, -db, -as)bibliothèque optimisée / debug / asan (+ libutils-dev-op, -db, -as) |
mingw64-libutils | Windows: mingw64-libutils-dev + mingw64-libutils-op, installed in the MinGW sysrootWindows : mingw64-libutils-dev + mingw64-libutils-op, installés dans le sysroot MinGW |
mingw64-libutils-op / -db | Windows optimized / debug library (+ mingw64-libutils-dev-op, -db), no asan with MinGWbibliothèque Windows optimisée / debug (+ mingw64-libutils-dev-op, -db), pas d'asan avec MinGW |
*-pre | pre-release channel, replaced by any release of the same version or highercanal pre-release, remplacé par toute release de version égale ou supérieure |
2.2 Integrate2.2 Intégrer
find_package(utils 4.1.0 REQUIRED)
target_link_libraries(${TARGET} PRIVATE utils::utils) # includes, static lib & OpenSSL
#define _Network
#define _Cli
#include <utils/utils.hpp>
The library linked follows the CMAKE_BUILD_TYPE of the project: Debug uses libutils_debug.a, Asan libutils_asan.a, anything else libutils.a; a missing package stops the configuration with the name of the package to install.La bibliothèque liée suit le CMAKE_BUILD_TYPE du projet : Debug utilise libutils_debug.a, Asan libutils_asan.a, le reste libutils.a ; un paquet manquant arrête la configuration en donnant le paquet à installer.
Same CMake code for Linux and Windows: configure the project with a MinGW toolchain whose CMAKE_FIND_ROOT_PATH is the MinGW sysroot (cmake/toolchain/mingw-w64.cmake of libutils, or /usr/share/mingw/toolchain-mingw64.cmake on Fedora) and find_package finds the mingw64-libutils* packages (utils::utils also links ws2_32). No Asan package with MinGW: build in Debug with mingw64-libutils-db.Même code CMake pour Linux et Windows : configurer le projet avec un toolchain MinGW dont le CMAKE_FIND_ROOT_PATH est le sysroot MinGW (cmake/toolchain/mingw-w64.cmake de libutils, ou /usr/share/mingw/toolchain-mingw64.cmake sur Fedora) et find_package trouve les paquets mingw64-libutils* (utils::utils lie aussi ws2_32). Pas de paquet Asan avec MinGW : compiler en Debug avec mingw64-libutils-db.
utils.hpp has no global guard: put the defines before every include of it, a bare include after a partial one only gets the sections already defined.utils.hpp n'a pas de garde globale : mettre les defines avant chaque include, un include nu après un include partiel n'obtient que les sections déjà définies.
3. Sections3. Sections
| Define | Namespace | ContentContenu |
|---|---|---|
_Exception | utils::exception | exceptions with a type and a code, formatted outputexceptions avec un type et un code, sortie formatée |
_Verbose | utils::verbose | atomic global level, locked output macrosniveau global atomique, macros de sortie verrouillées |
_Pool | utils::pool | Cluster<T>, Middlewares<T, U> |
_Cli | utils::cli | interactive command line: commands, history, hints, completion, hooks, middlewaresligne de commande interactive : commandes, historique, indices, complétion, hooks, middlewares |
_Arguments | utils::arguments | ArgParser (usages, flags, options, env), Settings (typed values, casts) |
_Network | utils::network | Server, Client, ISocket / ASocket / TCPSocket |
_Math | utils::math | coordinates, CFrame, point rotation, look vector, deg / radcoordonnées, CFrame, rotation de points, vecteur de visée, deg / rad |
_Concepts | utils::concepts | operation concepts (AddableWith, Comparable...)concepts d'opérations (AddableWith, Comparable...) |
_Encapsulation | utils::encapsulation | Pipe, Dup, Process, Poll, SharedObject, SharedMemory |
_System | utils::system | IdHandler, Scheduler, LoadBalancer |
_CustomType | utils::type | Vector2/3, OVector2/3, Matrix, OMatrix, BidirectionalLookupTable, Freezable, Worker |
_Manip | utils::iomanip, utils::smanip | ANSI sequences, format, FixedString, Base64Codec, EETPParserséquences ANSI, format, FixedString, Base64Codec, EETPParser |
_Algorithms | utils::algorithms | c2dmp-hsm (string distance), s.o.s (steganography)c2dmp-hsm (distance entre chaînes), s.o.s (stéganographie) |
_Security | utils::security | AESKey, RSAKey, CommonRSAKey, observers / memory leak notifierobservers / notifier de fuites mémoire |
_Platform | utils::platform | POSIX calls for Unix & Windows (close, socket, epoll_wait, dlopen, tcgetattr...), UTILS_UNIX / UTILS_WINDOWSappels POSIX pour Unix & Windows (close, socket, epoll_wait, dlopen, tcgetattr...), UTILS_UNIX / UTILS_WINDOWS |
_Attribute | macrosmacros | _hot, _nodiscard, _likely, _migration(x, y, z)... |
The full dependency view of the headers, classes and calls is on the graph page.La vue complète des dépendances entre en-têtes, classes et appels est sur la page graphe.
4. Errors4. Erreurs
Every error is an exception carrying a type and a code, never a return code. The codes are generated at the build from cmake/config/exceptions/**/*.json; a project adds its own codes (ExternalCode) with the same JSON format.Chaque erreur est une exception portant un type et un code, jamais un code de retour. Les codes sont générés au build depuis cmake/config/exceptions/**/*.json ; un projet ajoute ses propres codes (ExternalCode) avec le même format JSON.
| ClassClasse | Type | MeaningSens |
|---|---|---|
NoneException | None | not an error (ex: help displayed, Exit)pas une erreur (ex : aide affichée, Exit) |
WarningException | Warning | the program can continuele programme peut continuer |
ErrorException | Error | error of the callerreur de l'appel |
CustomException | givendonné | combination of typescombinaison de types |
FatalException | Fatal | prints and calls std::abort() from its constructoraffiche puis appelle std::abort() depuis son constructeur |
try {
server.start();
} catch (const utils::exception::IException& e) {
if (e.getCode() == utils::exception::InternalCode::AlreadyRunning) return;
std::cerr << e.formated() << std::endl; // [Error] file:line (origin) -> message / function = info
}
A code can restrict its allowed types; a forbidden combination ends with FatalException(ExceptionCodeRestriction). Many methods take failsafe (print a warning instead of throwing) or safe_mode (lock).Un code peut restreindre ses types autorisés ; une combinaison interdite finit en FatalException(ExceptionCodeRestriction). Beaucoup de méthodes prennent failsafe (avertir au lieu de lever) ou safe_mode (verrou).
5. Network & EETP5. Réseau & EETP
A Server and a Client exchange payloads (strings ended by a separator, '\n' by default) through a socket object. listen() reads what is available without blocking, join() waits for the next epoll event; stop() / kill() can be called from another thread. On Windows the sockets use Winsock 2 and the epoll is emulated over WSAPoll.Un Server et un Client échangent des payloads (chaînes terminées par un séparateur, '\n' par défaut) via un objet socket. listen() lit ce qui est disponible sans bloquer, join() attend le prochain événement epoll ; stop() / kill() peuvent être appelés depuis un autre thread. Sous Windows les sockets utilisent Winsock 2 et l'epoll est émulé avec WSAPoll.
5.1 EETP protocol5.1 Protocole EETP
EETPParser keeps the keys of each peer: the client sends SYN (its RSA public key, encrypted with the common RSA key of ~/.ssh/common), the server answers SO (a new AES-256 key, encrypted with the client key), then every message is AES-256-GCM encrypted with a new random iv.EETPParser garde les clés de chaque pair : le client envoie SYN (sa clé publique RSA, chiffrée avec la clé RSA commune de ~/.ssh/common), le serveur répond SO (une nouvelle clé AES-256, chiffrée avec la clé du client), puis chaque message est chiffré en AES-256-GCM avec un nouvel iv aléatoire.
| Type | DirectionSens | ContentContenu |
|---|---|---|
SYN | client → server | client RSA public key (common RSA)clé publique RSA du client (RSA commune) |
SO | server → client | AES-256 key (client RSA)clé AES-256 (RSA du client) |
| otherautre | ↔ | AES-256-GCM, frame <iv><tag> ETB <content>, Base64 encodedAES-256-GCM, trame <iv><tag> ETB <contenu>, encodée en Base64 |
EM | ↔ | disconnection, never encrypteddéconnexion, jamais chiffrée |
The framing changed in v3.0.0: both sides must use v3.0.0 or later.Le format des trames a changé en v3.0.0 : les deux côtés doivent utiliser v3.0.0 ou plus.
6. Processes & IPC6. Processus & IPC
Process wraps fork / execvp / waitpid with pipes and fd duplications applied in the child; Poll wraps epoll; SharedObject loads a .so. SharedMemory passes messages between processes through a POSIX shared memory split in slots. On Windows: CreateProcess, WSAPoll, LoadLibrary (.dll) and a file mapping with a named event (section 7).Process encapsule fork / execvp / waitpid avec pipes et duplications de fd appliquées dans le fils ; Poll encapsule epoll ; SharedObject charge un .so. SharedMemory fait passer des messages entre processus via une mémoire partagée POSIX découpée en slots. Sous Windows : CreateProcess, WSAPoll, LoadLibrary (.dll) et un file mapping avec un événement nommé (section 7).
read().Figure 3 : un écrivain réserve un slot libre (flag 0 → 1), écrit, le publie (flag 2) et réveille les lecteurs ; le thread lecteur de chaque instance copie les messages qui lui sont adressés dans un stockage local lu avec read().A message is addressed to one reader (Target(limit, ownership)) or to every reader (Target(limit), 0 = all the connected ones). An Id{id, ownership} links the answers of a conversation, join() waits for a message and returns when the memory is closed.Un message vise un lecteur (Target(limit, ownership)) ou tous (Target(limit), 0 = tous les connectés). Un Id{id, ownership} relie les réponses d'une conversation, join() attend un message et rend la main quand la mémoire est fermée.
7. Platforms7. Plateformes
Every class has the same API on Unix and Windows: the library only calls the system through utils::platform::, whose functions have the names, arguments and contract of POSIX (-1 and errno). On Unix they are the system calls, on Windows a Win32 / Winsock / CRT implementation. The same calls are given to the programs by the section _Platform.Chaque classe a la même API sous Unix et Windows : la bibliothèque n'appelle le système que via utils::platform::, dont les fonctions ont les noms, arguments et contrat de POSIX (-1 et errno). Sous Unix ce sont les appels système, sous Windows une implémentation Win32 / Winsock / CRT. Les mêmes appels sont donnés aux programmes par la section _Platform.
utils::platform.Figure 4 : un seul code pour les deux plateformes, la différence est dans utils::platform.7.1 Calls7.1 Appels
| HeaderEn-tête | CallsAppels | Windows implementationImplémentation Windows |
|---|---|---|
Unistd.hpp | close, read, write, pipe, dup, dup2, isatty, poll, getpid, readlink, strerror | CRT, or Winsock for a socket; poll also on the console / pipes / files; strerror knows the socket errorsCRT, ou Winsock pour un socket ; poll aussi sur la console / les pipes / les fichiers ; strerror connaît les erreurs de socket |
Socket.hpp | socket, connect, bind, listen, accept, recv, send, setsockopt, getsockname, getpeername, getaddrinfo | Winsock 2 started on the first use, errors translated in errnoWinsock 2 démarré au premier appel, erreurs traduites dans errno |
Epoll.hpp | epoll_create1, epoll_ctl, epoll_wait | emulation over WSAPoll: sockets only, level triggered, EPOLLONESHOT emulatedémulation avec WSAPoll : sockets seulement, niveau, EPOLLONESHOT émulé |
Dlfcn.hpp | dlopen, dlsym, dlclose, dlerror, dladdr | LoadLibraryA, GetProcAddress, FreeLibrary, GetModuleHandleExA |
Termios.hpp | tcgetattr, tcsetattr | console mode (ICANON = line input, ECHO, ISIG = ctrl+c, VT input)mode de la console (ICANON = saisie en ligne, ECHO, ISIG = ctrl+c, entrée VT) |
7.2 Differences7.2 Différences
No fork on Windows: Process::spawn() and a dup on a fd other than 0, 1, 2 raise a FatalException (UndefinedCall). spawn(path, args) uses CreateProcess.Pas de fork sous Windows : Process::spawn() et un dup sur un autre fd que 0, 1, 2 lèvent une FatalException (UndefinedCall). spawn(path, args) utilise CreateProcess.
Other differences: Poll / Client / Server only handle sockets (at most 10 ms of latency), a Process has no signal, ctrl+z is a char for the Cli, a SharedMemory disappears with its last handle. Include <windows.h> before <utils/utils.hpp> (it declares a member named _unused, a libutils macro), or define WIN32_LEAN_AND_MEAN.Autres différences : Poll / Client / Server ne gèrent que des sockets (10 ms de latence au plus), un Process n'a pas de signal, ctrl+z est un caractère pour le Cli, une SharedMemory disparaît avec son dernier handle. Inclure <windows.h> avant <utils/utils.hpp> (il déclare un membre nommé _unused, une macro de libutils), ou définir WIN32_LEAN_AND_MEAN.
8. Build, tests & CI8. Build, tests & CI
| CommandCommande | ResultRésultat |
|---|---|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Optimized|Debug|Asan | libutils.a / libutils_debug.a / libutils_asan.a |
cmake --build build --target release | the 3 librariesles 3 bibliothèques |
cmake --build build --target package_release | every RPM / DEB packagetous les paquets RPM / DEB |
-DBUILD_TESTS=ON + ctest --test-dir build | GoogleTest unit tests (unit_tests at the root)tests unitaires GoogleTest (unit_tests à la racine) |
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/mingw-w64.cmake | Windows build (MinGW-w64), tests run with wine by ctest, mingw64-libutils-* RPM/DEB packages (MinGW sysroot)build Windows (MinGW-w64), tests lancés avec wine par ctest, paquets RPM/DEB mingw64-libutils-* (sysroot MinGW) |
main or of a v* tag ([ignore] skips it).Figure 5 : la CI à chaque push sur main ou d'un tag v* ([ignore] la saute).| TriggerDéclencheur | ResultRésultat |
|---|---|
tag vX.Y.Ztag vX.Y.Z | stable packagespaquets stables |
tag vX.Y.Z-<suffix> or commit [build]tag vX.Y.Z-<suffixe> ou commit [build] | -pre packages (5 last versions kept)paquets -pre (5 dernières versions gardées) |
commit [release] or any package buildcommit [release] ou tout build de paquets | notification of docker-imagenotification de docker-image |
9. Licenses9. Licences
| ComponentComposant | LicenseLicence |
|---|---|
| libutils (its own code)libutils (son propre code) | MIT |
include/utils/algorithms/ (c2dmp-hsm, s.o.s) | CC BY-NC-SA 4.0 |
| OpenSSL | Apache-2.0 (linked, system package)Apache-2.0 (liée, paquet système) |
The MIT license doesn't apply to the dependencies: the synced algorithms can't be used commercially without an agreement with the author (THIRD_PARTY_NOTICES.md).La licence MIT ne s'applique pas aux dépendances : les algorithmes synchronisés ne peuvent pas être utilisés commercialement sans accord de l'auteur (THIRD_PARTY_NOTICES.md).