Net
Introduction
xpp::net provides Promise-based async TCP, UDP, DNS, URL parsing, and TLS configuration — wrapping libx's C APIs into C++ types.
#include <xpp/net/tcp.h>
#include <xpp/net/udp.h>
#include <xpp/net/url.h>
xpp::EventLoop loop;
xpp::WaitScope scope(loop);
using xpp::net::TcpStream;
using xpp::net::TcpListener;
// TCP echo server + client in one chain
auto server = TcpListener::bind("127.0.0.1:9090").await().unwrap();
auto client_p = TcpStream::connect("127.0.0.1:9090").then([](TcpStream c) {
return c.write("hi", 2).then([c](ssize_t) mutable {
char buf[64];
return c.read(buf, 64);
});
});
client_p.await();
Design Philosophy
-
Promise-based, poll-driven — All async ops return
Promise<T>.wait()drives the event loop; no separate runtime or reactor thread. -
Fast-path syscall + EAGAIN readiness —
recv/send/recv_from/send_totry the syscall immediately. On EAGAIN, they wait for readiness viaAsyncFdand retry. Zero Promise overhead when data is available. -
adapt() for one-shot ops —
lookup_host()usesadapt<T, Adapter>()— the adapter starts the async op in its constructor, cancels in its destructor, and theAdapterPromiseNodeowns the adapter.TcpStream::connect()usesasync() + new(self-deleting adapter) because libx'sxTcpConnecthas no cancel API. -
TLS is transparent — Pass
Option<const TlsContext&> = nonetoTcpStream::connect()to enable TLS. libx'sxTcpConnectdoes the handshake; the resultingTcpStreamtransparently encrypts/decrypts. No separateTlsConntype. -
RAII everywhere —
TcpStream,TcpListener,UdpSocket,Url,TlsContextall close/free their underlying resources in destructors. Move-only. -
C++11-compatible — All headers compile as C++11.
std::pair+std::tieforrecv_fromresults (C++17 users may use structured bindings).
Architecture
TCP UDP DNS URL/TLS
├── TcpStream ├── UdpSocket ├── lookup_host() ├── Url (sync)
│ ├── xTcpConn (libx) │ ├── int m_fd │ └── adapt() │ └── xUrl
│ ├── AsyncFd (readiness) │ └── AsyncFd └── LookupHostAdapter ├── TlsConfig
│ ├── connect via async()+new └── bind/recv_from/send_to └── TlsContext
├── TcpListener (RAII)
│ ├── xTcpListener
│ └── accept via adapt()
└── TLS via TlsContext
Modules
- TCP —
TcpStreamandTcpListener: Promise-based async TCP. - UDP —
UdpSocket: async UDP from scratch (libx has no UDP API). - DNS —
lookup_host(): async hostname resolution. - URL —
Url: RAII wrapper aroundxUrlwith structured errors. - TLS —
TlsConfigandTlsContext: RAII TLS configuration.
bind methods return Promise<io::Result<T, io::Error>> — see I/O Error for the error type.
Comparison with tokio::net
| Aspect | xpp::net | tokio::net |
|---|---|---|
| Async model | Poll-based Promise + wait() | async fn + .await |
| TCP connect | Promise<TcpStream> (async()+new) | Future<Result<TcpStream>> |
| Readiness | AsyncFd (edge-triggered) | mio (edge-triggered) |
| Fast path | ::read + EAGAIN → readiness | read + EAGAIN → readiness |
| TLS | Option<const TlsContext&> to connect() | TlsConnector::connect() |
| DNS | lookup_host() → Promise<vector<SocketAddr>> | lookup_host() → Future<impl Iterator> |
| UDP | recv_from → Promise<pair<ssize_t, SocketAddr>> | recv_from → Future<Result<(usize, SocketAddr)>> |
| Bind | Async (Promise<io::Result<T>>, DNS for hostnames) | Async (ToSocketAddrs may resolve) |
| Error type | io::Error (4 bytes, niche-optimized) | std::io::Error (heap-allocated) |
| Threading | Single-threaded | Multi-threaded runtime |