powpow/net/common

Search:
Group by:

Common networking utilities for powpow. This module provides platform-agnostic socket types, error handling, and helper functions for setting socket options and resolving addresses. It abstracts away differences between Windows and POSIX APIs, allowing powpow to use a consistent interface for network operations across platforms.

Types

KtlsMode = enum
  KtlsOff,                  ## Never request offload; all crypto stays in userspace.
  KtlsAuto,                 ## Request offload, silently fall back when unavailable.
  KtlsRequired ## Request offload and reject connections where it does
               ## not engage, so a silent regression to userspace crypto
               ## cannot masquerade as a working deployment.
How hard a SslContext tries to move TLS into the kernel. See configureKtls in net/tls.
NetError = object of CatchableError

Consts

DefaultBufSize = 4096
Default read buffer size per connection.
O_BINARY = 0'i32
O_RDONLY = 0
SEEK_CUR = 1
SEEK_END = 2
SEEK_SET = 0

Procs

proc closeFile(fd: int) {.inline, ...raises: [], tags: [], forbids: [].}
Close a file descriptor.
proc getFileSize(fd: int): int64 {....raises: [], tags: [], forbids: [].}
Get file size from an open fd. Returns -1 on error.
proc getSockLen(addrBuf: ptr Sockaddr_storage): SockLen {.inline, ...raises: [],
    tags: [], forbids: [].}
Return the correct socklen for the address family.
proc initNet() {....raises: [], tags: [], forbids: [].}
Initialize networking. Safe to call multiple times.
proc isIpAddress(address: string): bool {....raises: [], tags: [], forbids: [].}
True when address is a numeric IPv4 or IPv6 literal (no DNS needed).
proc ktlsRxInstalled(fd: SocketHandle): bool {.inline, ...raises: [], tags: [],
    forbids: [].}
True when the kernel decrypts this socket's receive path.
proc ktlsTxInstalled(fd: SocketHandle): bool {.inline, ...raises: [], tags: [],
    forbids: [].}
True when the kernel encrypts this socket's transmit path. Only such a socket may be handed raw sendfile(2) bytes.
proc ktlsUlpAttach(fd: SocketHandle): bool {.inline, ...raises: [], tags: [],
    forbids: [].}
Whether the tls ULP can be attached to this socket. False when the kernel module is absent (ENOENT) — the common case on a stock kernel, where modprobe tls is required.
proc lastSocketError(): cint {.inline, ...raises: [], tags: [], forbids: [].}
Get the last socket error (platform-agnostic).
proc openFileRead(path: string): int {....raises: [], tags: [], forbids: [].}
Open a file for reading. Returns fd or -1 on error. On Windows, force binary mode to prevent _read from treating 0x1A (Ctrl-Z) as EOF in binary files like videos/images.
proc readFile(fd: int; buf: ptr UncheckedArray[byte]; len: int): int64 {.
    ...raises: [], tags: [], forbids: [].}
Read up to len bytes from a file. Returns bytes read, 0 on EOF, -1 on error.
proc resolveAddr(address: string; port: int; sockType = SOCK_STREAM;
                 protocol = 0): Sockaddr_storage {....raises: [NetError], tags: [],
    forbids: [].}
Resolve address:port into the FIRST socket address ready for bind/connect. Works for both IPv4 and IPv6. For multi-address fallback use resolveAddrAll.
proc resolveAddrAll(address: string; port: int; sockType = SOCK_STREAM;
                    protocol = 0): seq[Sockaddr_storage] {....raises: [NetError],
    tags: [], forbids: [].}
Resolve address:port into ALL returned socket addresses (walks the addrinfo chain, so hosts with multiple A/AAAA records yield multiple candidates). The caller may try them in order for connect fallback.
proc seekFile(fd: int; offset: int64): int64 {....raises: [], tags: [], forbids: [].}
Seek to an absolute position in a file. Returns new position or -1 on error.
proc sendFileChunk(sockFd: SocketHandle; fileFd: int; fileOff: var int64;
                   remaining: var int64): int64 {....raises: [], tags: [],
    forbids: [].}
Send file data to a socket using zero-copy when available. Updates fileOff and remaining. Returns bytes sent, 0 on EAGAIN (caller should retry when socket is writable),
-1 on hard error.
proc setIpv6Only(fd: SocketHandle) {....raises: [], tags: [], forbids: [].}
Set IPV6_V6ONLY so an IPv6 wildcard socket does not also claim IPv4 (required to bind 0.0.0.0 and :: on the same port). No-op on Windows.
proc setNonBlocking(fd: SocketHandle) {....raises: [NetError], tags: [],
                                        forbids: [].}
Put a socket into non-blocking mode using a single ioctl syscall.
proc setReuseAddr(fd: SocketHandle) {....raises: [NetError], tags: [], forbids: [].}
Enable SO_REUSEADDR on a socket.
proc setReusePort(fd: SocketHandle) {....raises: [NetError], tags: [], forbids: [].}

Enable SO_REUSEPORT on a socket (macOS/Linux). No-op on Windows.

Note: this only permits the shared bind. On Linux and FreeBSD the kernel also load-balances the group, so one listen socket per worker works. On Darwin it does NOT: every connection is delivered to a single member of the group, and there is no SO_REUSEPORT_LB to change that (the option does not exist, so setting it fails with ENOPROTOOPT). Multi-worker servers on Darwin must therefore share one listen socket across workers instead — see proto/multithread.nim.

proc setTcpCork(fd: SocketHandle; enable: bool) {....raises: [], tags: [],
    forbids: [].}
Enable or disable TCP corking (TCP_CORK on Linux, TCP_NOPUSH on macOS/BSD). No-op on Windows and other unsupported platforms.
proc setTcpNoDelay(fd: SocketHandle) {....raises: [], tags: [], forbids: [].}
Disable Nagle's algorithm for lower latency. Silently ignores errors (e.g. on AF_UNIX sockets where TCP_NODELAY is not applicable).
proc sockaddrFromIp(ip: string; port: int): Sockaddr_storage {.
    ...raises: [NetError], tags: [], forbids: [].}
Build a socket address from a numeric IPv4/IPv6 literal without calling getaddrinfo (which blocks on the resolver). Raises NetError otherwise.
proc sockClose(fd: SocketHandle) {.inline, ...raises: [], tags: [], forbids: [].}
Close a socket.
proc sockInProgress(): bool {.inline, ...raises: [], tags: [], forbids: [].}
proc sockInterrupted(): bool {.inline, ...raises: [], tags: [], forbids: [].}
proc sockRecv(fd: SocketHandle; buf: pointer; bufLen: int): int {.inline,
    ...raises: [], tags: [], forbids: [].}
Read from a socket. Returns bytes read, 0 on EOF, negative on error.
proc sockSend(fd: SocketHandle; buf: pointer; len: int): int {.inline,
    ...raises: [], tags: [], forbids: [].}
Write to a socket. Returns bytes written, negative on error.
proc sockShutdown(fd: SocketHandle; how: cint) {.inline, ...raises: [], tags: [],
    forbids: [].}
Shut down part of a full-duplex connection.
proc sockWouldBlock(): bool {.inline, ...raises: [], tags: [], forbids: [].}
proc sockWritev(fd: SocketHandle; iov: ptr IOVec; iovcnt: int): int {.inline,
    ...raises: [], tags: [], forbids: [].}
Scatter-gather write. On Windows there is no synchronous writev, so a loop of send() calls (one per iovec) would cost N syscalls vs 1 on POSIX — the HTTP response path routinely builds ~7 iovecs. Coalesce small writes into a single send() call instead.