powpow

This is a high-performance, event notification library for Nim. It provides a low-level event loop and timer wheel, as well as higher-level abstractions for building TCP/UDP, HTTP and WebSocket servers.

The library is designed to be minimal and efficient, with a focus on low-latency event handling and minimal overhead, providing a solid foundation for building high-performance networked applications in Nim.

Features

Core Event Loop (loop.nim)

  • Single-threaded non-blocking reactor
  • I/O multiplexing via kqueue (macOS/BSD), epoll (Linux), IOCP (Windows), poll (fallback), or the opt-in Linux io_uring backend (io/)
  • 4-level hierarchical timer wheel — O(1) insert/fire/cancel
  • One-shot and repeating interval timers
  • Deferred callbacks (executed before each I/O poll iteration)
  • Idle handlers (executed when no I/O events are pending)
  • Pointer-based fd watcher dispatch — zero hash-table lookups on the hot path
  • Generation-counter stale event detection
  • Dead watcher sweep with zombie/retired list for in-flight event safety
  • Thread-safe stop() via eventfd (Linux) or self-pipe (macOS/BSD)
  • Buffer pool for shared read buffers
  • Adaptive event capacity scaling (min 64, max 4096)

TCP Networking (net/tcp.nim)

  • Non-blocking TCP server with connection pooling
  • Non-blocking TCP client with async connect (DNS resolved on the loop)
  • Edge-triggered I/O events
  • Write buffering with automatic corking (TCP_CORK / TCP_NOPUSH)
  • Scatter-gather writes via writev
  • Zero-copy file send via sendfile (Linux sendfile, macOS sendfile, POSIX fallback)
  • Graceful shutdown with close-after-drain (closeAfterDrain)
  • Unix domain socket support (macOS/BSD/Linux)
  • SO_LINGER{0} for fast shutdown
  • Per-connection read buffer pooling

Async DNS (net/dns.nim)

  • In-loop DNS resolver (RFC 1035) — no blocking getaddrinfo, no worker threads
  • Reads /etc/hosts and /etc/resolv.conf (system resolver config)
  • A + AAAA queries with A-fallback; retries with timeout/attempts
  • TTL-based result cache + negative caching
  • resolveAddr (callback) / resolveAddrAsync (awaitable Future) for users; connect uses it automatically
  • Numeric IP literals resolve inline (zero DNS I/O)

OS Signals (signal.nim)

  • In-process SignalRelay pub/sub bus (listen / listenOnce / unlisten)
  • watchOsSignal/watchOsSignals deliver real OS signals through the loop
  • OsSignal enum: SIGHUP, SIGINT, SIGQUIT, SIGUSR1/2, SIGPIPE, SIGALRM, SIGTERM, SIGURG, SIGCHLD, SIGIO
  • Platform-native delivery: signalfd (Linux), self-pipe (macOS/BSD/POSIX), SetConsoleCtrlHandler Ctrl+C (Windows) — no global signal handlers
  • Graceful shutdown on SIGINT/SIGTERM without blocking the loop

Stream I/O (stream.nim)

  • IoStream wraps an arbitrary non-blocking fd and drives it from the loop
  • Pipes, subprocess stdout, UDS and socketpair IPC; newStreamPair creates a full-duplex channel
  • Connection-style write path: direct write drained until EAGAIN, remainder buffered and flushed on Write events; 32 MiB queued-write cap
  • pause/resume read backpressure (a paused reader blocks the pipe writer)
  • close is the single terminal transition and fires onClose exactly once; closeAfterWrite flushes then delivers EOF to the peer
  • POSIX only (Windows IOCP is sockets-only); regular files work on kqueue but epoll rejects them

UDP Networking (net/udp.nim)

  • Non-blocking UDP server (bind) and client (connect)
  • recvfrom / sendto for connectionless communication
  • Connected UDP sockets for peer-scoped send/recv

HTTP/1.1 Parser (proto/http.nim)

  • Incremental, zero-copy parser — materialize strings lazily from byte offsets
  • O(1) method dispatch via first-byte switch
  • Pipelined request support
  • Streaming body handling via callback
  • Chunked transfer encoding
  • Body streaming to file
  • Multipart form data support

HTTP Server (proto/httpserver.nim)

  • Implement your-own-router — lower-level callback-based design
  • OnRequestCallback* = proc(req: HttpRequest, res: HttpResponse) {.gcsafe.}
  • Higher-level frameworks implement routing on top of this callback
  • Streaming response body
  • Static file serving with MIME type detection
  • Conditional requests (If-Modified-Since, If-None-Match)
  • Range requests with 206 Partial Content
  • Directory listing
  • CORS headers
  • Streaming multipart upload handling
  • Pipelined request-response processing

WebSocket (proto/ws.nim)

  • RFC 6455 compliant
  • Standalone WebSocket server mode
  • HTTP upgrade from HttpServer routes
  • Text, binary, ping/pong, and close frames
  • Per-message deflate extension
  • Masked frame handling

Multi-threaded HTTP Server (proto/multithread.nim)

  • SO_REUSEPORT kernel-level connection distribution
  • One event loop + listen socket per worker thread
  • Zero cross-thread communication — no single-threaded acceptor bottleneck
  • Graceful shutdown via shutdown pipe

SIMD-Accelerated Scanning (proto/simdscan.nim)

  • SSE2-accelerated CRLF detection
  • Scalar fallback for non-x86 architectures

Platform Abstraction (platform/)

  • kqueue — macOS/BSD (high-performance, edge-triggered)
  • epoll — Linux (with eventfd wake)
  • iocp — Windows (I/O Completion Ports)
  • poll — POSIX fallback
  • io/ — Linux io_uring backend (submission-based, opt-in). Enabled with nimble --features:io_uring <cmd>, requires "powpow[io_uring]", or nim c -d:powpowIoUring. The same public API, driven by IORING_OP_ACCEPT/RECV/SEND/CONNECT/SEND_ZC/SPLICE/... completions instead of readiness events; the generic fd-watcher API is emulated with one-shot IORING_OP_POLL_ADD. Ships the full io_uring API binding (io/uring.nim), IORING_REGISTER_PROBE feature detection, zero-copy SEND_ZC and SPLICE file sends, and registered buffers (IORING_REGISTER_BUFFERS). Requires Linux >= 5.6.

Networking Common (net/common.nim)

  • Platform-agnostic socket API and address resolution (IPv4 + IPv6)
  • Socket options: non-blocking, SO_REUSEADDR, SO_REUSEPORT, TCP_NODELAY
  • sendfile zero-copy file transmission
  • Kernel-TLS (kTLS) state queries — Linux only, ktlsSupported
  • Cross-platform error handling (EAGAIN, EINPROGRESS, etc.)
  • Auto-initialization (WSAStartup on Windows, SIGPIPE ignore on POSIX)

TLS (net/tls.nim)

  • OpenSSL 3.x, non-blocking handshake driven by the event loop; server (implicit or STARTTLS-style) and client, implicit TLS and ALPN
  • Opt-in kernel-TLS offload via configureKtls: KtlsOff (default), KtlsAuto (request, fall back silently) or KtlsRequired (drop the connection rather than quietly serve in userspace crypto)
  • With TX offload engaged, sendFile/serveFile reach a real sendfile(2) on the TLS socket instead of a read + SSL_write loop. ktlsTxActive/ktlsRxActive/ktlsActive report what a live connection is actually doing
  • Offload needs the tls kernel module (modprobe tls), OpenSSL built with enable-ktls, a kTLS-capable cipher, and the socket-BIO backend (not io_uring, which runs TLS over memory BIOs). Everywhere else, and whenever anything is missing, powpow uses userspace TLS unchanged

Exports

==, Callback, EventType, FdCallback, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, ObserverCallback, TimerCallback, TimerId, TlsState, iouEnabled, ==, Callback, EventType, FdCallback, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, ObserverCallback, Platform, PlatformEvent, TimerCallback, TimerId, TlsState, add, ensureCapacity, init, iouEnabled, modify, poll, remove, wake, ==, Callback, EventType, FdCallback, FdWatcher, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, Loop, Observer, ObserverCallback, Platform, PlatformEvent, TimerCallback, TimerId, TlsState, acquireBuf, add, addCleanup, addIdle, addInterval, addTimer, addTurnEndHook, cancelObserver, cancelTimer, close, close, deferCall, ensureCapacity, init, iouEnabled, isRunning, modify, modify, monoMs, newLoop, observe, pauseTimer, poll, poll, pollNowMs, pollWallSec, postToLoop, register, releaseBuf, remove, removeIdle, resumeTimer, run, runOnce, stop, timerCount, unregister, unregisterFd, wake, ==, Callback, Connection, ConnState, DefaultBufSize, DefaultSendFileChunk, DnsCacheEntry, DnsCallback, DnsError, DnsQuery, DnsResolver, DtlsConfig, DtlsContext, DtlsError, DtlsHandshakeTimeoutDefaultMs, DtlsIdleTimeoutDefaultMs, DtlsMaxChunk, DtlsMaxSessionsDefault, DtlsMtuDefault, DtlsRole, DtlsServer, DtlsSession, DtlsSessionState, DtlsSweepIntervalDefaultMs, EventType, FdCallback, FdWatcher, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, IoStream, IoStreamState, KtlsMode, Loop, MaxBufPoolSize, MaxConnPoolSize, MaxIoStreamWriteBuffer, MxCallback, MxRecord, NetError, O_BINARY, Observer, ObserverCallback, OnAccept, OnClose, OnData, OnError, OnUdpData, O_RDONLY, Platform, PlatformEvent, ResolvedIp, SEEK_CUR, SEEK_END, SEEK_SET, SendFileChunkSize, SslContext, SslError, TcpServer, TimerCallback, TimerId, TlsRole, TlsState, TxtCallback, TxtRecord, UdpSocket, UNIX_PATH_MAX, acquireBuf, add, addCleanup, addIdle, addInterval, addTimer, addTurnEndHook, adoptListenFd, alpnSelected, bindUdp, bindUdp, cancelObserver, cancelSendFile, cancelTimer, close, close, close, close, close, close, close, close, closeAfterDrain, closeAfterSend, closeAfterWrite, closeAndRelease, closeDns, closeFile, configureDns, configureKtls, connect, connect, connectDtls, connectHe, connectHe, connectUdp, connectUdp, connectUnix, connectUnix, continueSendFile, createListenSocket, defaultDtlsConfig, deferCall, disableKtls, driveHandshake, enableKtls, ensureCapacity, finCloseNow, flushWriteBuffer, formatIp, getClientIp, getClientSockAddr, getFileSize, getLoop, getLoop, getLoop, getLoop, getSockLen, init, initNet, injectFd, iouEnabled, isIpAddress, isRunning, isTlsActive, ktlsActive, ktlsRxActive, ktlsRxInstalled, ktlsRxOffloaded, ktlsSupported, ktlsTxActive, ktlsTxInstalled, ktlsTxOffloaded, ktlsUlpAttach, lastSocketError, listen, listenUnix, maxBufPoolSize, maxConnPoolSize, maxWriteBufferSize, modify, modify, monoMs, newClientDtlsContext, newClientTlsContext, newConnection, newDtlsServer, newLoop, newServerDtlsContext, newServerTlsContext, newStreamPair, newStreamPair, newTcpServer, newTcpServer, observe, openFileRead, openStream, openStream, pause, pauseTimer, peerAddrStr, poll, poll, pollNowMs, pollWallSec, postToLoop, readFile, refreshKtlsState, register, releaseBuf, remove, removeIdle, resolveAddr, resolveAddr, resolveAddrAll, resolveAddrAsync, resolveAddrAsync, resolveAddrBoth, resolveAddrBothAsync, resolveAddrBothAsync, resolveMx, resolveMxAsync, resolveMxAsync, resolveTxt, resolveTxtAsync, resolveTxtAsync, resume, resumeTimer, run, run, run, run, run, runOnce, seekFile, send, send, send, send, send, send, sendFile, sendFileActive, sendFileChunk, sendTo, sendTo, sendTo, sendTo, sendTo, sendv, sessionCount, setAlpnProtocols, setDnsServers, setIpv6Only, setNonBlocking, setReuseAddr, setReusePort, setTcpCork, setTcpNoDelay, shutdown, sockaddrFromIp, sockClose, sockInProgress, sockInterrupted, sockRecv, sockSend, sockShutdown, sockWouldBlock, sockWritev, start, startUnix, stop, stop, stop, stop, stop, timerCount, tlsFree, tlsRead, tlsWrite, unregister, unregisterFd, wake, wrapTls, write, write, ==, AsyncHttpClient, BodyStream, Callback, Connection, ConnHttp, ConnState, DefaultBodyBuf, DefaultChunkSize, DefaultIdleTimeoutMs, DefaultKeepAliveMs, DefaultMaxFrameSize, DefaultMaxIdlePerHost, DefaultMaxIdleTotal, DefaultMaxPending, DefaultMaxResponseBody, DefaultReadTimeoutMs, DefaultTimeoutSweepMs, EventType, FdCallback, FdWatcher, H2ClientCallback, H2ClientConn, H2ClientMaxStreamsHint, H2ClientPool, H2ClientResponse, H2Conn, H2ConnectionPreface, H2DefaultMaxBody, H2DefaultMaxConcurrent, H2DefaultMaxFrameSize, H2DefaultMaxHeaderList, H2DefaultWindowSize, H2Error, H2ErrorCode, H2FlagAck, H2FlagEndHeaders, H2FlagEndStream, H2FlagPadded, H2FlagPriority, H2Frame, H2FrameHeaderLen, H2FrameParser, H2FrameType, H2MaxFrameSizeMax, H2MaxFrameSizeMin, H2MaxWindowSize, H2Request, H2Response, H2Role, H2SendBufCap, H2Server, H2Setting, H2SettingsId, H2Stream, H2StreamState, HpackContext, HpackDefaultTableSize, HpackError, HpackHeader, HpackMaxStringLen, HpackStaticTableLen, HttpBodyCallback, HttpClient, HttpClientBase, HttpClientResponse, HttpConnect, HttpConnPool, HttpDelete, HttpError, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpParser, HttpPatch, HttpPost, HttpPut, HttpRequest, HttpResponse, HttpServer, HttpServerOptions, HttpTrace, Loop, MaxBufPoolSize, MaxConnPoolSize, MaxHeaders, MaxHeaderSize, MaxRequestLine, MaxStreamBodySize, MaxWsPoolSize, MinStreamBodySize, MultiThreadH2Server, MultiThreadHttpServer, Observer, ObserverCallback, OnAccept, OnClose, OnData, OnError, OnH2RequestCallback, OnProxyClose, OnProxyConnect, OnProxyData, OnProxyError, OnProxyUpstreamConnect, OnRequestCallback, ParsePhase, Platform, PlatformEvent, PooledConn, PoolKey, ProxyDir, ProxyPair, ProxyServer, RateLimiter, TcpServer, TimerCallback, TimerId, TlsState, WindowLimit, WsCloseCb, WsConnection, WsError, WsErrorCb, WsFrameKind, WsMessageCb, WsOpenCb, WsServer, acquireBuf, add, addCleanup, addConnection, addIdle, addInterval, addTimer, addTurnEndHook, adoptListenFd, adoptListenFd, allow, appendBytes, applyOptions, bodyView, buildHandshakeResponse, cancelObserver, cancelSendFile, cancelTimer, check, close, close, close, close, close, close, close, close, close, close, close, close, close, close, close, close, closeAfterDrain, closeAfterSend, closeAll, closeAndRelease, closeWs, computeAcceptKey, connect, connect, connectH2, connectH2Tls, connectHe, connectHe, connectUnix, connectUnix, connectWs, continueSendFile, createListenSocket, decode, decodeGoaway, decodeInt, decodePing, decodePriority, decodeRstStream, decodeSettings, decodeString, decodeWindowUpdate, defaultHttpServerOptions, deferCall, delete, delete, delete, delete, drainChunk, driveHandshake, emptyH2Body, encode, encodeData, encodeFrame, encodeFrameInto, encodeGoaway, encodeHeaders, encodeInt, encodeIntInto, encodeInto, encodePing, encodePingAck, encodePriority, encodeRstStream, encodeSettings, encodeSettingsAck, encodeString, encodeStringInto, encodeWindowUpdate, ensureCapacity, ensureH2FlushHook, ensureTcpServer, error, feed, feed, feed, feedH2, finalizeCloseDelimited, finCloseNow, flushSendBuf, flushStagedH2, flushWriteBuffer, formatIp, frameTypeFromInt, get, get, get, get, getBody, getBody, getBody, getBodyStream, getBodyString, getBodyString, getBodyView, getClientIp, getClientIp, getClientIp, getClientSockAddr, getConn, getConnectionClose, getConnectionClose, getConnectionClose, getContentLength, getContentLength, getContentLength, getFileExt, getHeaders, getHeaders, getHeaders, getHeaderValue, getHeaderValue, getHttpMinor, getLoop, getLoop, getLoop, getLoop, getLoop, getLoop, getLoop, getMethod, getMultipart, getPath, getProtocol, getQuery, getRemainingData, getRequest, getStatusCode, getStatusCode, getStatusText, getStatusText, getTrailer, getTrailer, getTrailers, getTrailers, getUrl, h2Closed, h2Draining, handshakeCount, hasTrailers, hasTrailers, head, head, head, head, header, header, headerBytes, headersDone, hpackError, huffmanDecode, huffmanEncode, huffmanEncodeInto, idleConnections, idleConnections, idleConnectionsFor, init, initHuffman, injectFd, iouEnabled, isBytesUnit, isChunked, isComplete, isError, isEstablished, isOk, isRunning, ktlsActive, ktlsRxOffloaded, ktlsTxActive, ktlsTxOffloaded, listen, listen, listen, listen, listen, listen, listen, listen, listen, listenUnix, listenUnix, listenUnix, markSent, maxBufPoolSize, maxConnPoolSize, maxWriteBufferSize, modify, modify, monoMs, newAsyncHttpClient, newConnection, newH2ClientPool, newH2Conn, newH2FrameParser, newH2Server, newH2Server, newHpackContext, newHttpClient, newHttpConnPool, newHttpParser, newHttpServer, newHttpServer, newHttpServer, newLoop, newMultiRateLimiter, newMultiThreadH2Server, newProxyServer, newProxyServer, newProxyServer, newRateLimiter, newTcpServer, newTcpServer, newWsConnection, newWsServer, newWsServer, observe, onClientData, onClose, onClose, onConnect, onData, onError, onError, onMessage, onOpen, onUpstreamConnect, onUpstreamData, openClientStream, options, options, options, options, parseRange, parseWsFrames, parseWsUrl, patch, patch, patch, patch, patchFrameHeader, pauseTimer, peekAll, peekChunk, peekContentType, peekMethod, peekPath, pendingBytes, phase, poll, poll, pollNowMs, pollWallSec, pop, populatePools, post, post, post, post, postToLoop, push, put, put, put, put, readChunk, readChunkInto, readChunkString, refreshKtlsState, register, releaseBuf, remove, removeFromPool, removeIdle, removeSession, request, request, request, request, request, request, request, request, requestImpl, reserveFrameHeader, reset, reset, reset, resetForNext, resolveReal, resumeTimer, run, run, run, run, run, run, runOnce, send, send, send, send, send, send, sendBinary, sendError, sendFile, sendFile, sendFileActive, sendHandshake, sendHandshakeRequest, sendMessage, sendMessage, sendPing, sendPong, sendText, sendv, serveFile, serveStatic, setError, setKeepAliveTimeout, setMaxConnections, setMaxPending, setMaxTableSize, setUpstream, setUpstreamUnix, shutdown, stageFrame, stageFrame, start, start, start, start, start, start, start, start, start, start, start, start, start, start, startClientPreface, startUnix, status, status, stop, stop, stop, stop, stop, stop, stop, streamFile, streamToFile, tcpServer, tcpServer=, teardownByUpstreamFd, timerCount, tlsFree, tlsRead, tlsWrite, tryAdvance, unregister, unregisterFd, upgradeToWs, wake, websocketUpgrade, withinRoot, writeDisposition, writeFrame, writeFrameMasked, wsPoolAdd, wsPoolPop, ListenerHandle, OsSignal, SIG_BLOCK, SignalRelay, close, emit, getLoop, listen, listen, listenOnce, listenOnce, newOsSignalRelay, newOsSignalRelay, newSignalRelay, newSignalRelay, run, signalNumber, stop, unlisten, watchOsSignal, watchOsSignals, FileSystemEvent, FileWatcher, FileWatcherCb, close, getLoop, newFileWatcher, newFileWatcher, run, stop, ==, Callback, EventType, FdCallback, HeartbeatMs, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, ObserverCallback, ThreadPool, ThreadPoolError, TimerCallback, TimerId, TlsState, closeThreadPool, getLoop, iouEnabled, newThreadPool, shutdownThreadPool, submitWork, ==, Callback, DefaultMaxFrameSize, DefaultWsReconnectPolicy, EventType, FdCallback, FdWatcher, HttpConnect, HttpDelete, HttpGet, HttpHead, HttpMethod, HttpOptions, HttpPatch, HttpPost, HttpPut, HttpTrace, Loop, Observer, ObserverCallback, Platform, PlatformEvent, SslContext, SslError, TimerCallback, TimerId, TlsRole, TlsState, WsClient, WsCloseCb, WsConnection, WsError, WsErrorCb, WsFrameKind, WsGiveUpCb, WsMessageCb, WsOpenCb, WsReconnectPolicy, WsRetryCb, WsServer, acquireBuf, add, addCleanup, addIdle, addInterval, addTimer, addTurnEndHook, alpnSelected, attemptCount, buildHandshakeResponse, cancelObserver, cancelTimer, close, close, close, close, closeWs, computeAcceptKey, configureKtls, connect, connect, connectWs, deferCall, disableKtls, enableKtls, ensureCapacity, getLoop, getProtocol, handshakeCount, init, iouEnabled, isConnected, isEstablished, isRunning, isTlsActive, ktlsActive, ktlsRxActive, ktlsSupported, ktlsTxActive, listen, modify, modify, monoMs, newClientTlsContext, newLoop, newServerTlsContext, newWsClient, newWsConnection, newWsServer, newWsServer, observe, onClose, onClose, onError, onError, onGiveUp, onMessage, onMessage, onOpen, onOpen, onRetry, parseWsFrames, parseWsUrl, pauseTimer, poll, poll, pollNowMs, pollWallSec, postToLoop, register, releaseBuf, remove, removeIdle, reset, resumeTimer, run, run, runOnce, sendBinary, sendHandshake, sendHandshakeRequest, sendMessage, sendMessage, sendMessage, sendMessage, sendPing, sendPong, sendText, session, setAlpnProtocols, setTlsContext, start, stop, stop, timerCount, unregister, unregisterFd, upgradeToWs, wake, websocketUpgrade, wrapTls, writeFrame, writeFrameMasked