[+] Linux: missing AuNet adapter API
[*] Update README
This commit is contained in:
parent
1e4082c02f
commit
6f6be5c545
272
README.md
272
README.md
@ -1,6 +1,4 @@
|
|||||||
## PREALPHA (in-dev, missing polish and APIs are volatile)
|
## PREALPHA
|
||||||
## Minimum viable product ETA: September 2022
|
|
||||||
|
|
||||||
## AuroraRuntime
|
## AuroraRuntime
|
||||||
|
|
||||||
The Aurora Runtime is a low level platform abstraction layer for modern cross-platform C++
|
The Aurora Runtime is a low level platform abstraction layer for modern cross-platform C++
|
||||||
@ -14,26 +12,30 @@ pipeline to get started.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Reduced C++ standard template library dependence (^1)
|
- Reduced C++ standard template library dependence despite requiring a modern-ish driver (^1) (portable when?)
|
||||||
- High performance threading and synchronization primitives (os userland sched optimized)
|
- Logging; UTF-8 logger, common sink backends, formating interface
|
||||||
- Async even driven subsystem with high perf sync primitives
|
- Debug and Telementry; asserts, panics, exception logging, demangling of symbols, more
|
||||||
- Abstract kernel file/net transaction, IPC, timer, semaphore, et al abstraction in the form of LoopQueues (eg, MacOS RunLoops)
|
- Crypto ECC/[25519, P-384, P-256], [AES, RSA, X509], CBC[AES, Stinky3DES], HMAC, HashCash, BCrypt, [common digests]
|
||||||
- Asynchronous and synchronous IO (network, character, file, buffered, process, and io watcher)
|
|
||||||
- Optional event driven async programming paradigm
|
|
||||||
- Consoles; graphical and standard, file archives
|
|
||||||
- Logging; UTF-8 logger, common sink backends
|
|
||||||
- Debug and Telementry; asserts, exception logging, fio, nio backends
|
|
||||||
- Crypto ECC/[25519, P-384, P-256], [AES, RSA, X509], [common digests]
|
|
||||||
- Basic cmdline parsing from any module
|
- Basic cmdline parsing from any module
|
||||||
- Exit and fatal save condition callbacks
|
- Exit and fatal save condition callbacks
|
||||||
- IPC
|
- Random; secure, user-seeded, and fast
|
||||||
- Network [WIP]
|
- Hardware Info; memory and cpu info (including cpu feature bits, core topology, e-core awareness, and basic cache size)
|
||||||
- Random; secure and fast
|
- Software stack information for retrieving kernel, version, brand, family, build string, etc
|
||||||
- Hardware Info; memory and cpu info (including features, topology, e-core, and cache info)
|
- Compression (deflate, gzip, zstd, LZ4, bzip2, TODO: lzma, brotli)
|
||||||
- Software Stack Info (kernel, version, brand, build string, etc)
|
|
||||||
- FIO settings registry
|
|
||||||
- Compression
|
|
||||||
- Locale and encoding
|
- Locale and encoding
|
||||||
|
- High performance threading and synchronization primitives (os userland sched optimized)
|
||||||
|
- Async subsystem backed by high performance sync primitives (cv loop) and hybrid switching into IO polling (think userland cv-backed promises + waitmultipleobjects)
|
||||||
|
- IO subsystem for standard cross-platform IO loop queues, IPC (mutex with auto-unlock, semaphores, full-duplex single-connection pipes, and shared memory), file (direct uncached access), and network
|
||||||
|
- Abstract kernel IO transactions, IPC objects, timers, semaphores, and others in the form of ILoopSources
|
||||||
|
- Common IO transaction interface for network, file, and handle async access (with workarounds for platform querks)
|
||||||
|
- IO processor for common network, pipe processing, and general work on any given thread (think of it as an io context)
|
||||||
|
- IO pipe processor for the processing of data when invoked by io transactions and other signalable interfaces
|
||||||
|
- Protocol stack concept, for implementing low-overhead IO stream processors, where data is streamed through layers of interceptors
|
||||||
|
- Builtin support for TLS and compression in the form of protocol stack interceptors
|
||||||
|
- Non-locking file system watchers with IO subsystem interoperability
|
||||||
|
- Process spawning with stream redirection backed by the IO subsystem
|
||||||
|
- Process memory management with IPC and file mapping
|
||||||
|
- FIO settings registry
|
||||||
- C++ utility templates and macros
|
- C++ utility templates and macros
|
||||||
- Follows all strings are UTF-8 convention
|
- Follows all strings are UTF-8 convention
|
||||||
|
|
||||||
@ -55,36 +57,28 @@ Discord: [Invite](https://discord.gg/XYjCGWWa4J)
|
|||||||
|
|
||||||
| Platform | Support |
|
| Platform | Support |
|
||||||
| ----------- | ------- |
|
| ----------- | ------- |
|
||||||
| NT/Win32-like |✅ |
|
| NT/Win7 | ⚠️ |
|
||||||
|
| NT/Win8.1+ | ✅ |
|
||||||
| NT/UWP | 🕖 |
|
| NT/UWP | 🕖 |
|
||||||
| NT/GameOS|❌ |
|
| NT/GameOS|❌ |
|
||||||
| Linux |🕖 |
|
| Linux | ✅ |
|
||||||
| FreeBSD 9 | ❌ |
|
| FreeBSD 9 | ❌ |
|
||||||
| FreeBSD 11 | ❌ |
|
| FreeBSD 11 | ❌ |
|
||||||
|
| OpenBSD | ❌ |
|
||||||
| XNU/NS-like | ❌ |
|
| XNU/NS-like | ❌ |
|
||||||
|
|
||||||
|
Win7: some apis are inherently limited before Win8.1.
|
||||||
|
For client applications, win7 should not be crippled.
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
|
|
||||||
Performance of each system should ideally be that of the best implementation on the platform,
|
Performance of each system should ideally be that of the best implementation on the platform,
|
||||||
and no worse than the STL. Due to heavyweight requirements and spiral model defined objectives,
|
and no worse than the STL. Due to heavyweight requirements and spiral model defined objectives,
|
||||||
a handful of portable C libraries have been brought into achieve compression, crypto, alloc, and
|
a handful of unknown good industry standard libraries have been brought into achieve compression,
|
||||||
str formatting objectives using known good industry standard libraries. Footprint is expected to
|
crypto, alloc, and formatting objectives. Footprint is expected to be on the heavier side for optimal
|
||||||
be on the heavier side for optimal performance (incl toll for C++ tradeoffs) and flexibility.
|
performance (incl toll for C++ tradeoffs), usability, and flexibility.
|
||||||
|
|
||||||
|
|
||||||
Runtime as of 2022-02-01 *without the wxWidgets toolkit, with all compression libraries* on Windows LTSC 2019:
|
|
||||||
|
|
||||||
DLL Disk: 4.2MB \
|
|
||||||
Size Of Image: 0x50B000 (5MB) \
|
|
||||||
Real Commit Charge of a Console App: 9.7MB \
|
|
||||||
...the task manager lie: 3,168K (3.1MB -> less than our DLL) \
|
|
||||||
...HWInfo reports
|
|
||||||
|
|
||||||
[13:07:38] [Info] | RamInfo Private Allocation: 10215424/71987290112 (^1) \
|
|
||||||
[13:07:38] [Info] | RamInfo Address Space: 11669504/71987290112
|
|
||||||
|
|
||||||
^1 ...on LTSC 2019. Modern Windows 10 and 11 will return the exact task manager value of 3,168K (3.1MB).
|
|
||||||
|
|
||||||
|
|
||||||
Defer to benchmarks
|
Defer to benchmarks
|
||||||
|
|
||||||
@ -201,9 +195,8 @@ resources.
|
|||||||
|
|
||||||
## IO
|
## IO
|
||||||
|
|
||||||
The Aurora Runtime implements a multiple io wait loop sub-subsystem, file io, network io,
|
The Aurora Runtime implements loop, file io, network io, and other sub-subsystems with
|
||||||
various adapters and connectors, io processors, io/character, io/buffered, and other such
|
various adapters and connectors.
|
||||||
concepts to aid with writing low-level cross-platform IO.
|
|
||||||
|
|
||||||
An important note about texting encoding. Stdin, file encoding, text decoders, and other IO
|
An important note about texting encoding. Stdin, file encoding, text decoders, and other IO
|
||||||
resources work with codepage UTF-8 as the internal encoding scheme. String overloads and
|
resources work with codepage UTF-8 as the internal encoding scheme. String overloads and
|
||||||
@ -212,16 +205,22 @@ to read a BOM to translate any other arbitrary user generated text input to UTF-
|
|||||||
|
|
||||||
### Loop
|
### Loop
|
||||||
|
|
||||||
The Aurora Runtime implements a kernel-scheduler optimized IO subsystem for managing GUIs,
|
The Aurora Runtime implements a kernel-scheduler optimized IO loop subsystem for managing GUIs;
|
||||||
Network AIO, File AIO, IPC AIO, and thread synchronization objects through loop the loop subsystem.
|
network, file, ipc AIO; and thread synchronization objects for when these waitables converse.
|
||||||
|
|
||||||
ILoopSource is an interface defined by the loop subsystem for IO objects with a signalable state.
|
ILoopSource is an interface defined by the loop subsystem for IO objects with a signalable state.
|
||||||
Attached to an ILoopQueue, the ILoopQueue will provide wait-on and similar functionality; and
|
Attached to an ILoopQueue, the ILoopQueue will provide wait-any/wait-all/is-signaled polling with
|
||||||
subscription notifications of signal state change. ILoopQueue's are thread-safe allowing for
|
optional subscription functionality. Furthermore, ILoopQueues are thread-safe allowing for cross-thread
|
||||||
cross-thread or mid-wait work scheduling. Subscription notifications allow for optimized loop
|
or mid-wait work scheduling (as in, the addition of new subscribers during sleep or callback).
|
||||||
source removal or no-action/non-removal replies from subscription implementer. In addition to
|
|
||||||
the synchronization provided by the ILoopQueue, the ILoopSource interface permits arbitrary
|
It is possible to run loop queues like a poll object or with an arbitrary amount of optional
|
||||||
is-signaled-and-latch (TryLock) queries and timed-wait (WaitOn) calls on a per IO object basis.
|
subscribers per loop source.
|
||||||
|
|
||||||
|
Subscription notifications allow for optimized loop source removal or no-action/non-removal replies
|
||||||
|
from subscription implementer. If you and all other subscribers want to evict the ILoopSource,
|
||||||
|
the source will be automatically removed from the ILoopQueue. If just you vote to evict, you will
|
||||||
|
no longer receive updates for the object, but the ILoopSource and other subscribers will remain.
|
||||||
|
|
||||||
|
|
||||||
### IPC
|
### IPC
|
||||||
|
|
||||||
@ -233,16 +232,28 @@ are used to implement IPC within the applications namespace/sandbox.
|
|||||||
|
|
||||||
### FIO
|
### FIO
|
||||||
|
|
||||||
A simple file stream interface is provided by an Open function which accepts an Aurora path and
|
A simple blocking file stream is provided by an open function given an Aurora path string and a
|
||||||
an advisory lock level. However, all such functions are blocking in face of platform specific
|
file advisory lock level. This object can be used with AuProcess to map regions of the file into
|
||||||
asynchronous alternatives. An alternative `IAsyncFileStream` is provided to supply the user with
|
the address map. However, everything about this object is blocking.
|
||||||
an supplier of `IAsyncTransaction`'s - an overlapped IO style interface for starting a read/write
|
|
||||||
transaction, registering an APC-like callback, requesting a loop subsystem waitable object, and
|
An alternative asynchronous IAsyncFileStream interface is available which supplies IO transaction
|
||||||
clearing the request. AIO is backed by `io_submit` under Linux, POSIX AIO under BSD, and Overlapped
|
objects for scheduling direct disk reads. One should be careful to note each platform has file AIO
|
||||||
IO under NT. A glibc approach of spamming threads akin to libuv and skipping the synchronization
|
querks. For instance...
|
||||||
on completion step isn't our style. Instead, you are reliant on the native async capabilities of the
|
|
||||||
underlying operating system. Special consideration must be made for alignment, cached/uncached access,
|
- Linux will block on most file systems if metadata has to be poked
|
||||||
and supported file systems.
|
- FS support is limited (NT/NTFS > Linux/XFS > NT/xxxx (w/ caching) > Linux/EXT4 > unsupported)
|
||||||
|
- Read/Writes musts be made with respect to sector alignment
|
||||||
|
- Removing caching on Linux will mitigate blocking behaviour (~O_DIRECT blocking io_submit)
|
||||||
|
- ...but caching on Win32 is sometimes desirable
|
||||||
|
- Linux reads might be limited by max_sectors_kb or max_segments
|
||||||
|
|
||||||
|
For large block reads: \
|
||||||
|
bDirectIO = true; read directly from fs (recommend) \
|
||||||
|
offsets -> must align
|
||||||
|
|
||||||
|
When data is small enough for file caches to be useful: \
|
||||||
|
bDirectIO = !AuBuild::kIsNtDerived (recommend) \
|
||||||
|
offsets -> align for the highest denominator
|
||||||
|
|
||||||
Additional utility functions exist outside of the two file interfaces for: stat, directory iteration,
|
Additional utility functions exist outside of the two file interfaces for: stat, directory iteration,
|
||||||
UTF-8 string reading and writing, blocking binary read/writes, and more.
|
UTF-8 string reading and writing, blocking binary read/writes, and more.
|
||||||
@ -265,10 +276,16 @@ All string paths are simply expanded, similar to MSCRT's `fullpath` or UNIX's `r
|
|||||||
| `\` | Agnostic Directory Splitter |
|
| `\` | Agnostic Directory Splitter |
|
||||||
| `.` [SPLITTER] | Nothing |
|
| `.` [SPLITTER] | Nothing |
|
||||||
|
|
||||||
|
### TLS
|
||||||
|
|
||||||
|
TLS client and partial server support is provided by protocol stack interceptors meaning that our implementation is no-socket.
|
||||||
|
It's possible to write into a buffered protocol stack using the provided stream writer, simulating data coming through a socket channel;
|
||||||
|
and to fetch the response/translated message using an end protocol piece to be supplied with the data, or using the provided stream reader to read the end
|
||||||
|
to read the end interceptors buffer once the protocol stack has been ticked.
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
The Aurora Runtime provides reports system, application, and user specific paths under the `Aurora::IO::FS` subsystem.
|
The Aurora Runtime provides system, application, and user specific paths under the `Aurora::IO::FS` subsystem.
|
||||||
These include the users home directory, a per vendor sandboxed application user directory, a per vendor sandboxed application
|
These include the users home directory, a per vendor sandboxed application user directory, a per vendor sandboxed application
|
||||||
all users directory, the user-installable program directory, the user's real home directory, and other such relevant paths.
|
all users directory, the user-installable program directory, the user's real home directory, and other such relevant paths.
|
||||||
|
|
||||||
@ -285,44 +302,47 @@ The Aurora Runtime provides child process monitoring, asynchronous child stdin/o
|
|||||||
|
|
||||||
## Locale
|
## Locale
|
||||||
|
|
||||||
Encoding and decoding of UTF-8, UTF-16, UTF-32, GBK, GB-2312, and SJIS is supported through platform provided decoders.
|
Encoding and decoding of UTF-8, UTF-16, UTF-32, GBK, GB-2312, and SJIS is supported through OS provided decoders.
|
||||||
System localization information, including system codepage, country, and system language, is provided by the envrionment variables which
|
System localization information, including system codepage, country, and system language, is provided by the available
|
||||||
are available, OS specific interfaces, or the user overload mechanism.
|
envrionment variables, OS specific interfaces, or the overload mechanism.
|
||||||
|
|
||||||
## Memory
|
## Memory
|
||||||
|
|
||||||
### Allocator
|
### Allocator
|
||||||
|
|
||||||
Objects are allocated across API/Module boundaries. So long as the high level API design isn't horribly inefficient to an extent
|
Objects are allocated across API/module boundaries using an ABI defined by Aurora Runtime.
|
||||||
that cache invalidation and indirect lookups are minimalized, object-heavy code can optimized. On modern hardware, legitmate indirect
|
|
||||||
branching versus short jumps aren't so expensive between modules in real world usage; and in combination with a fast enough allocator,
|
|
||||||
there is little reason why couldn't achieve reasonable OOP performance through a C-with-classes-like API.
|
|
||||||
|
|
||||||
As for allocation, we generally expect a dependence on Microsoft's mimalloc. Linking against the Aurora Runtime in the Aurora
|
Such OOP design in contrast to header-everything is contingent on well-defined interface boundaries which make sense from a
|
||||||
Ecosystem will automatically replace global allocators with `Aurora::Memory`, which in turn, proxies any other suitable allocator
|
perspective of optimizaton (primarily allocation and indirect branching) and usability.
|
||||||
interface with extended zero, array, and alignment respecting APIs. A suitably fast allocator, such as mimalloc, should reduce the
|
|
||||||
cost of the OOP design.
|
Allocations are optimized by using a known good third party library, mimalloc. In the future, it should be possible to replace the
|
||||||
|
standard allocator; however, for now all allocations are routed through Aurora::Memory which is backed by mi_xxxx calls.
|
||||||
|
Mimalloc and/or other such slab and zone based allocators can and must be explored as an optimization for C++'s tendency to
|
||||||
|
arbitrary allocate memory. This should improve the performance of reasonbly written modules with OOP in mind.
|
||||||
|
|
||||||
|
Indirect branches are optimized by simply trying to design APIs that arent complete ass for humans and systems to work with.
|
||||||
|
|
||||||
### Memory Heap
|
### Memory Heap
|
||||||
|
|
||||||
Aurora provides a heap allocator for dividing up a large preallocated region of memory
|
Aurora provides a heap allocator for dividing up a large preallocated region of memory.
|
||||||
|
|
||||||
|
Currently, we use a modified version of O(1) heap that provides a constant worst case allocation and deallocation
|
||||||
|
of any given request. Memory is provided by AuProcess for the requested allocation, but AuMemory might be unfortunately
|
||||||
|
hit during the initialization of a heap.
|
||||||
|
|
||||||
|
|
||||||
### Shared Pointers
|
### Shared Pointers
|
||||||
|
|
||||||
Memory objects, including shared pointers, and the object allocation model is defined by AuROXTL. The `AuSPtr` class template
|
Memory objects, including shared pointers, and the object allocation model is defined by AuROXTL. The `AuSPtr` class template
|
||||||
is backed by the standard `std::shared_ptr`, extended by `#include <auROXTL/auMemoryModel.hpp>,` in the default configuration.
|
is backed by the standard `std::shared_ptr`, extended by `#include <auROXTL/auMemoryModel.hpp>,` in the default configuration.
|
||||||
|
|
||||||
AuROXTL memory primitives, and most STL containers, are source compatible with the base STL classes, such that any Aurora
|
The reason we wrap shared pointers is two folds
|
||||||
specific behaviour is lost during type reduction.
|
1) in code that doesn't need to be fast, we can simply hack in is valid checks on assignment or use an interface with panic branches
|
||||||
|
to handle null access conditions.
|
||||||
There are benefits of using the Aurora extended classes, include redefining null dereference on shared ptrs to throw
|
2) in the future, it may be desirable to use established AuEnableSharedOnThis, AuSharedFromThis, etc idoms to migrate existing code
|
||||||
an AU_THROW_STRING. Without support for native behaviour within the C++ driver, such features are rather expensive using the performace
|
to an alternative non-std::shared_ptr backed system.
|
||||||
hacks we have available (outside of ripping the compiler apart to emit special debug info for hacky trap handlers). Arguably, it's an
|
|
||||||
experiment worth trying now that modern hardware can make up for software and microcode flaws; and architecture translation. Most users
|
|
||||||
probably wont even notice the performance loss, until it saves them from a hard crash and they realize dereferences are bloated.
|
|
||||||
This is default behaviour, and can be easily disabled or configured from within your ecosystem's AuroraConfiguration.h to globally
|
|
||||||
modify the behaviour and subsequent ABI of the AuSPtr's.
|
|
||||||
|
|
||||||
|
AuSPtr and friends are reducable and constructible from and from their std::shared_ptr/unique counterparts.
|
||||||
|
|
||||||
```
|
```
|
||||||
Types:
|
Types:
|
||||||
@ -342,34 +362,11 @@ Macros:
|
|||||||
AuFunction<...> AuBindThis(This_t *::?, ...)
|
AuFunction<...> AuBindThis(This_t *::?, ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Defer to [auROXTL](https://git.reece.sx/AuroraSupport/auROXTL) for more information
|
||||||
### Note
|
|
||||||
Aurora provides a bring your own container and shared pointer model overloadable in your configuration header.<br>
|
|
||||||
User-overloadable type declerations and generic access utilities are defined under [auROXTL](https://git.reece.sx/AuroraSupport/auROXTL)
|
|
||||||
|
|
||||||
|
|
||||||
## Debug
|
## Debug
|
||||||
|
|
||||||
### Error Markers
|
|
||||||
|
|
||||||
SysPushError[EFailureCategory shorthand] can be used to include additional side-channel telemetry
|
|
||||||
information about the execution of a program. SysPushError_(...) takes a string format sequence and
|
|
||||||
a variadic sequence of substitute values - or no arguments whatsoever.
|
|
||||||
|
|
||||||
#### Example:
|
|
||||||
```cpp
|
|
||||||
IBufferedCharacterConsumer *BufferConsumerFromProviderNew(const AuSPtr<ICharacterProvider> &provider)
|
|
||||||
{
|
|
||||||
if (!provider)
|
|
||||||
{
|
|
||||||
SysPushErrorArg("Missing ICharacterProvider");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return _new BufferedCharacterConsumer(provider);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Asserts
|
### Asserts
|
||||||
|
|
||||||
[TODO]
|
[TODO]
|
||||||
@ -385,38 +382,46 @@ Debug and Release (debug and optimized ship-with-debug) assertions:
|
|||||||
SysAssertDbg(AuFunction{}, "unexpected default function")
|
SysAssertDbg(AuFunction{}, "unexpected default function")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Something went wrong
|
### Error stack
|
||||||
|
|
||||||
You should ensure AuDebug::CheckErrors() or a SysPushError-like function is called to ensure enchanced TLS-state telemetry is
|
```cpp
|
||||||
captured. AuDebug::PrintErrors() will print the the errors gathered by the debug subsystem for telemetry purposes. These may
|
TEST(ErrorStack, A)
|
||||||
include the crts errno, the last reported posix return value, the last Win32 error code, and/or last reported microkernel error.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
Try/Catch:
|
|
||||||
```
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
AuErrorStack errors;
|
||||||
|
|
||||||
|
SysPushErrorIO("Something something IO error");
|
||||||
|
SysPushErrorIO("Something something IO error 1");
|
||||||
|
SysPushErrorIO("Something something IO error 2 {}", "hello worlds");
|
||||||
|
|
||||||
|
ASSERT_TRUE(errors.HasCaptured());
|
||||||
|
ASSERT_TRUE(errors.HasMultipleOccurred());
|
||||||
|
ASSERT_TRUE(errors.FirstMessage()->pNextThreadMesage);
|
||||||
|
ASSERT_TRUE(errors.FirstMessage()->pNextThreadMesage->pNextThreadMesage);
|
||||||
|
|
||||||
|
AuLogDbg("{}, {}, {}",
|
||||||
|
*errors.ToString(),
|
||||||
|
errors.FirstMessage()->pNextThreadMesage->ToString(),
|
||||||
|
errors.FirstMessage()->pNextThreadMesage->pNextThreadMesage->ToString());
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
|
TEST(ErrorStack, B)
|
||||||
{
|
{
|
||||||
SysPushErrorCatch(); // THIS IS NOT REQUIRED FOR EXCEPTION TELEMETRY
|
AuErrorStack errors;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AU_THROW_FORMATTED("hello people {}", 23423423);
|
||||||
|
//throw "hello modern platforms";
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(errors.HasCaptured());
|
||||||
|
AuLogDbg("{}", *errors.ToString());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
[More](https://gitea.reece.sx/AuroraSupport/HelloAurora/src/branch/master/Tests/Public/19.%20Hello%20Debug/Main.cpp)
|
||||||
|
|
||||||
|
|
||||||
Windows System Error Messages: \
|
|
||||||
CRT:
|
|
||||||
```cpp
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
POSIX:
|
|
||||||
```cpp
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Binding
|
## Binding
|
||||||
|
|
||||||
Aurora Runtime provides C++ APIs; however, it should be noted that two libraries are used to extend interfaces and enums
|
Aurora Runtime provides C++ APIs; however, it should be noted that two libraries are used to extend interfaces and enums
|
||||||
@ -448,9 +453,12 @@ can lead to some memory leaks.
|
|||||||
|
|
||||||
## Aurora Async
|
## Aurora Async
|
||||||
|
|
||||||
The Aurora Runtime offers an optional asynchronous task driven model under the AuAsync namespace. Featuring promises,
|
[TODO]
|
||||||
thread group pooling, functional-to-task wrapping, and task-completion callback-task-dispatch idioms built around 3
|
- Promises
|
||||||
concepts.
|
- Thread Pool
|
||||||
|
- Optional shutdown on work exhaustion
|
||||||
|
- Wait for task[s] completion builtin to work objects
|
||||||
|
- IO subsystem interop
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
#include "AuNetAdapter.hpp"
|
#include "AuNetAdapter.hpp"
|
||||||
#include "AuNetEndpoint.hpp"
|
#include "AuNetEndpoint.hpp"
|
||||||
|
|
||||||
|
#include <asm/types.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
namespace Aurora::IO::Net
|
namespace Aurora::IO::Net
|
||||||
{
|
{
|
||||||
AuString NetAdapter::GetHostname()
|
AuString NetAdapter::GetHostname()
|
||||||
@ -22,13 +27,478 @@ namespace Aurora::IO::Net
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698
|
||||||
|
|
||||||
|
struct NetlinkDevice
|
||||||
|
{
|
||||||
|
NetlinkDevice();
|
||||||
|
~NetlinkDevice();
|
||||||
|
|
||||||
|
bool Connect();
|
||||||
|
|
||||||
|
AuSInt Send(const void *pBuffer, size_t uLength);
|
||||||
|
AuSInt Recv(void *pBuffer, size_t uLength);
|
||||||
|
|
||||||
|
AuList<NetAdapter> GetAdaptersForFamily(sa_family_t family);
|
||||||
|
AuList<AuPair<int, NetEndpoint>> ReadRoutes(int index, int family, AuString &name);
|
||||||
|
|
||||||
|
void UpdateAdapterInfo(int family, NetAdapter &adapter);
|
||||||
|
|
||||||
|
int fd { -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
static NetlinkDevice gNetlinkDevice;
|
||||||
|
|
||||||
|
NetlinkDevice::NetlinkDevice()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NetlinkDevice::~NetlinkDevice()
|
||||||
|
{
|
||||||
|
if (this->fd != -1)
|
||||||
|
{
|
||||||
|
::close(this->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetlinkDevice::Connect()
|
||||||
|
{
|
||||||
|
sockaddr_nl nladdr {};
|
||||||
|
|
||||||
|
this->fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
|
if (this->fd < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = ::fcntl(this->fd, F_GETFL, 0);
|
||||||
|
if (flags != -1)
|
||||||
|
{
|
||||||
|
::fcntl(this->fd, F_SETFL, flags | FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
nladdr.nl_family = AF_NETLINK;
|
||||||
|
if (::bind(this->fd, (struct sockaddr *) &nladdr, sizeof(nladdr)) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSInt NetlinkDevice::Send(const void *pBuffer, size_t uLength)
|
||||||
|
{
|
||||||
|
sockaddr_nl nladdr {};
|
||||||
|
msghdr msg {};
|
||||||
|
iovec vec {};
|
||||||
|
|
||||||
|
nladdr.nl_family = AF_NETLINK;
|
||||||
|
|
||||||
|
msg.msg_name = &nladdr;
|
||||||
|
msg.msg_namelen = sizeof(nladdr);
|
||||||
|
vec.iov_base = (char *)pBuffer;
|
||||||
|
vec.iov_len = uLength;
|
||||||
|
msg.msg_iov = &vec;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
return ::sendmsg(fd, &msg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSInt NetlinkDevice::Recv(void *pBuffer, size_t uLength)
|
||||||
|
{
|
||||||
|
sockaddr_nl nladdr {};
|
||||||
|
msghdr msg {};
|
||||||
|
iovec vec;
|
||||||
|
|
||||||
|
nladdr.nl_family = AF_NETLINK;
|
||||||
|
|
||||||
|
msg.msg_name = &nladdr;
|
||||||
|
msg.msg_namelen = sizeof(nladdr);
|
||||||
|
vec.iov_base = pBuffer;
|
||||||
|
vec.iov_len = uLength;
|
||||||
|
msg.msg_iov = &vec;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
auto ret = ::recvmsg(fd, &msg, 0);
|
||||||
|
if (msg.msg_flags & MSG_TRUNC)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addr_t
|
||||||
|
{
|
||||||
|
sa_family_t family;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
in_addr in_addr;
|
||||||
|
in6_addr in6_addr;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
AuList<NetAdapter> NetlinkDevice::GetAdaptersForFamily(sa_family_t family)
|
||||||
|
{
|
||||||
|
static const auto kRouteBufferSize = 12 * 1024;
|
||||||
|
|
||||||
|
struct nlmsghdr *hdr;
|
||||||
|
struct rtmsg *rt;
|
||||||
|
ssize_t len;
|
||||||
|
size_t reqlen;
|
||||||
|
|
||||||
|
reqlen = NLMSG_SPACE(sizeof(*rt));
|
||||||
|
auto pReq = AuMakeSharedArray<AuUInt8>(kRouteBufferSize);
|
||||||
|
|
||||||
|
hdr = (struct nlmsghdr *)pReq.get();
|
||||||
|
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*rt));
|
||||||
|
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||||
|
hdr->nlmsg_type = RTM_GETROUTE;
|
||||||
|
|
||||||
|
rt = (struct rtmsg *)NLMSG_DATA(hdr);
|
||||||
|
rt->rtm_family = family;
|
||||||
|
rt->rtm_table = RT_TABLE_MAIN | RT_TABLE_LOCAL;
|
||||||
|
|
||||||
|
if (this->Send(pReq.get(), reqlen) < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pResp = AuMakeSharedArray<AuUInt8>(kRouteBufferSize);
|
||||||
|
if (!pResp)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AuList<NetAdapter> ret;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
len = this->Recv(pResp.get(), kRouteBufferSize);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hdr = (struct nlmsghdr *)pResp.get();
|
||||||
|
NLMSG_OK(hdr, len);
|
||||||
|
hdr = NLMSG_NEXT(hdr, len))
|
||||||
|
{
|
||||||
|
NetAdapter adapter;
|
||||||
|
|
||||||
|
if (hdr->nlmsg_type == NLMSG_DONE)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->nlmsg_type == NLMSG_ERROR)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
rt = (struct rtmsg *)NLMSG_DATA(hdr);
|
||||||
|
|
||||||
|
auto attr = RTM_RTA(rt);
|
||||||
|
auto attrlen = RTM_PAYLOAD(hdr);
|
||||||
|
for (; RTA_OK(attr, attrlen); attr = RTA_NEXT(attr, attrlen))
|
||||||
|
{
|
||||||
|
const size_t expectedAddressLength = (family == AF_INET) ? 4 : 16;
|
||||||
|
|
||||||
|
size_t dstlen = RTA_PAYLOAD(attr);
|
||||||
|
|
||||||
|
switch (attr->rta_type)
|
||||||
|
{
|
||||||
|
case RTA_GATEWAY:
|
||||||
|
case RTA_DST:
|
||||||
|
case RTA_SRC:
|
||||||
|
{
|
||||||
|
if (dstlen != expectedAddressLength)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetEndpoint ep;
|
||||||
|
addr_t *address2 = (addr_t*)ep.hint;
|
||||||
|
address2->family = family;
|
||||||
|
|
||||||
|
AuMemcpy(&address2->u.in_addr, RTA_DATA(attr), dstlen);
|
||||||
|
DeoptimizeEndpoint(ep);
|
||||||
|
|
||||||
|
if (attr->rta_type == RTA_GATEWAY)
|
||||||
|
{
|
||||||
|
adapter.gateway = ep.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr->rta_type == RTA_DST)
|
||||||
|
{
|
||||||
|
adapter.address = ep.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RTA_OIF:
|
||||||
|
{
|
||||||
|
adapter.index = *(int*)RTA_DATA(attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.push_back(adapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuList<AuPair<int, NetEndpoint>> NetlinkDevice::ReadRoutes(int index, int family, AuString &name)
|
||||||
|
{
|
||||||
|
static const auto kAddrBufferSize = 12 * 1024;
|
||||||
|
|
||||||
|
AuList<AuPair<int, NetEndpoint>> ret;
|
||||||
|
nlmsghdr *hdr {};
|
||||||
|
ifaddrmsg *ifa {};
|
||||||
|
ssize_t len;
|
||||||
|
size_t reqlen;
|
||||||
|
|
||||||
|
/* Allocate space for the request. */
|
||||||
|
reqlen = NLMSG_SPACE(sizeof(*ifa));
|
||||||
|
auto pReq = AuMakeSharedArray<AuUInt8>(kAddrBufferSize);
|
||||||
|
|
||||||
|
hdr = (struct nlmsghdr *)pReq.get();
|
||||||
|
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa));
|
||||||
|
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||||
|
hdr->nlmsg_type = RTM_GETADDR;
|
||||||
|
|
||||||
|
ifa = (struct ifaddrmsg *)NLMSG_DATA(hdr);
|
||||||
|
ifa->ifa_family = family;
|
||||||
|
ifa->ifa_index = index;
|
||||||
|
|
||||||
|
if (this->Send(pReq.get(), reqlen) < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pResp = AuMakeSharedArray<AuUInt8>(kAddrBufferSize);
|
||||||
|
if (!pResp)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
len = this->Recv(pResp.get(), kAddrBufferSize);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hdr = (struct nlmsghdr *)pResp.get(); NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len))
|
||||||
|
{
|
||||||
|
if (hdr->nlmsg_type == NLMSG_DONE)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->nlmsg_type == NLMSG_ERROR)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ifa = (struct ifaddrmsg *)NLMSG_DATA(hdr);
|
||||||
|
if ((ifa->ifa_family != family) ||
|
||||||
|
(ifa->ifa_index != index))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifa->ifa_scope != RT_SCOPE_UNIVERSE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attr = IFA_RTA(ifa);
|
||||||
|
auto attrlen = RTM_PAYLOAD(hdr);
|
||||||
|
for (; RTA_OK(attr, attrlen); attr = RTA_NEXT(attr, attrlen))
|
||||||
|
{
|
||||||
|
size_t dstlen = RTA_PAYLOAD(attr);
|
||||||
|
const size_t addrlen = (family == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr);
|
||||||
|
|
||||||
|
if (attr->rta_type == IFA_LABEL)
|
||||||
|
{
|
||||||
|
name = (const char *)RTA_DATA(attr);
|
||||||
|
}
|
||||||
|
else if (addrlen == dstlen)
|
||||||
|
{
|
||||||
|
NetEndpoint ep;
|
||||||
|
addr_t *address2 = (addr_t*)ep.hint;
|
||||||
|
address2->family = family;
|
||||||
|
|
||||||
|
AuMemcpy(&address2->u.in_addr, RTA_DATA(attr), addrlen);
|
||||||
|
DeoptimizeEndpoint(ep);
|
||||||
|
ret.push_back(AuMakePair(attr->rta_type, ep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlinkDevice::UpdateAdapterInfo(int family, NetAdapter &adapter)
|
||||||
|
{
|
||||||
|
static const auto kAddrBufferSize = 12 * 1024;
|
||||||
|
|
||||||
|
nlmsghdr *hdr {};
|
||||||
|
ifinfomsg *ifa {};
|
||||||
|
|
||||||
|
auto reqlen = NLMSG_SPACE(sizeof(*ifa));
|
||||||
|
auto pReq = AuMakeSharedArray<AuUInt8>(kAddrBufferSize);
|
||||||
|
|
||||||
|
hdr = (struct nlmsghdr *)pReq.get();
|
||||||
|
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa));
|
||||||
|
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||||
|
hdr->nlmsg_type = RTM_GETLINK;
|
||||||
|
|
||||||
|
ifa = (struct ifinfomsg *)NLMSG_DATA(hdr);
|
||||||
|
ifa->ifi_family = family;
|
||||||
|
ifa->ifi_index = adapter.index;
|
||||||
|
|
||||||
|
if (this->Send(pReq.get(), reqlen) < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pResp = AuMakeSharedArray<AuUInt8>(kAddrBufferSize);
|
||||||
|
if (!pResp)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
auto len = this->Recv(pResp.get(), kAddrBufferSize);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
SysPushErrorIO("netlink error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hdr = (struct nlmsghdr *)pResp.get(); NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len))
|
||||||
|
{
|
||||||
|
if (hdr->nlmsg_type == NLMSG_DONE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->nlmsg_type == NLMSG_ERROR)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifa = (struct ifinfomsg *)NLMSG_DATA(hdr);
|
||||||
|
if ((ifa->ifi_index != adapter.index))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attr = IFLA_RTA(ifa);
|
||||||
|
auto attrlen = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
|
||||||
|
|
||||||
|
for (; RTA_OK(attr, attrlen); attr = RTA_NEXT(attr, attrlen)) {
|
||||||
|
|
||||||
|
size_t dstlen = RTA_PAYLOAD(attr);
|
||||||
|
|
||||||
|
const size_t addrlen = (family == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr);
|
||||||
|
|
||||||
|
if (attr->rta_type == IFLA_IFNAME)
|
||||||
|
{
|
||||||
|
adapter.device = (const char *)RTA_DATA(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: we can pull MTU and other stats from here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AuList<AuSPtr<INetAdapter>> GetForFamily(int family)
|
||||||
|
{
|
||||||
|
AuList<AuSPtr<INetAdapter>> ret;
|
||||||
|
if (gNetlinkDevice.fd == -1)
|
||||||
|
{
|
||||||
|
if (!gNetlinkDevice.Connect())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AuList<IPAddress> dups;
|
||||||
|
auto adapters = gNetlinkDevice.GetAdaptersForFamily(family);
|
||||||
|
for (auto &adapter : adapters)
|
||||||
|
{
|
||||||
|
gNetlinkDevice.UpdateAdapterInfo(family, adapter);
|
||||||
|
|
||||||
|
auto pAdapter = AuMakeShared<NetAdapter>(adapter);
|
||||||
|
if (!pAdapter)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bBreak = false;
|
||||||
|
|
||||||
|
auto ips = gNetlinkDevice.ReadRoutes(adapter.index, family, pAdapter->name);
|
||||||
|
for (const auto &[type, endpoint] : ips)
|
||||||
|
{
|
||||||
|
if (type == IFA_ANYCAST)
|
||||||
|
{
|
||||||
|
pAdapter->anycast = endpoint.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IFA_ADDRESS)
|
||||||
|
{
|
||||||
|
bBreak |= AuExists(dups, endpoint.ip);
|
||||||
|
dups.push_back(endpoint.ip);
|
||||||
|
pAdapter->address = endpoint.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IFA_BROADCAST)
|
||||||
|
{
|
||||||
|
pAdapter->broadcast = endpoint.ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bBreak)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.push_back(pAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv4s()
|
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv4s()
|
||||||
{
|
{
|
||||||
return {};
|
return GetForFamily(AF_INET);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv6s()
|
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv6s()
|
||||||
{
|
{
|
||||||
return {};
|
return GetForFamily(AF_INET6);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -56,7 +56,7 @@ namespace Aurora::IO::Net
|
|||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#if defined(AURORA_PLATFORM_LINUX)
|
#if defined(AURORA_PLATFORM_LINUX)
|
||||||
//return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user