std/tls
The TLS server transport: listen, accept, and run the server handshake. The client half (TlsStream, fetch) is in std/fetch, and std/https is the HTTP server built on this module. Importing it pulls in OpenSSL; std/net and std/http stay free of it.
from "std/tls" import { TlsListener, TlsConn }API reference
TlsConn
pub struct TlsConnOne accepted TLS connection. The server-side counterpart of std/fetch's TlsStream; separate from it because the two differ where it matters — a client owns its SSL_CTX and verifies the peer, a server's ctx belongs to the listener and is shared.
LIFETIME: ctx is deliberately absent. The SSL_CTX comes from the TlsListener and is shared by every connection it accepts, so freeing it here would pull it out from under the next accept(). The listener must outlive the connections it hands out.
TlsConn.readMoreBy
fn TlsConn.readMoreBy(self: &TlsConn, raw: &mut string, by: i64): i64recvOnce that gives up at by (epoch ms, 0 = never), appending to raw: the byte count, 0 once the peer has closed or the read failed, -1 at the deadline. That is std/http's request-reader contract (see readMoreBy there), so a TLS client that stalls mid-request is dropped like a plaintext one. Needs the fd nonblocking, which acceptWithin leaves it.
TlsConn.recv
fn TlsConn.recv(self: &TlsConn): Result<string, NetError>Read to EOF, as one string. For a request framed by the peer closing its write half; an HTTP server wants recvOnce().
TlsConn.recvOnce
fn TlsConn.recvOnce(self: &TlsConn): stringA single SSL_read of whatever has arrived. A server must answer while the client still holds the connection open, so a read-to-EOF loop would deadlock; this returns after one record — the TLS analogue of one read(2) on the socket.
TlsConn.send
fn TlsConn.send(self: &TlsConn, data: &string): Result<i64, NetError>Write data through the TLS record layer. Returns the byte count OpenSSL accepted.
TlsConn.sendWithin
fn TlsConn.sendWithin(self: &TlsConn, data: &string, ms: i64): Result<i64, NetError>send that stops waiting on a peer that is not reading once ms has passed (0 = no limit).
TlsListener
pub struct TlsListenerListening TLS socket: a TCP listener plus the server SSL_CTX holding the certificate chain and private key. Frees the ctx and closes the fd on drop.
TlsListener.accept
fn TlsListener.accept(self: &TlsListener): Result<TlsConn, NetError>Accept one connection and run the server handshake on it.
TlsListener.acceptWithin
fn TlsListener.acceptWithin(self: &TlsListener, ms: i64): Result<TlsConn, NetError>accept() whose handshake must finish within ms of the TCP accept (0 = no limit). Without it a client that connects and sends nothing parks the handshake forever, and a server accepting one connection at a time (std/https) stops answering everyone. The connection comes back nonblocking, for readMoreBy and sendWithin; recvOnce/recv/send assume a blocking fd outside a green task, so use those on a connection from accept().
TlsListener.addr4
fn TlsListener.addr4(self: &TlsListener): Option<u32>The bound IPv4 address, or None for an IPv6 socket (or a failed getsockname).
TlsListener.bind
fn TlsListener.bind(port: u16, certPath: &string, keyPath: &string): Result<TlsListener, NetError>Bind 0.0.0.0:port and serve certPath (PEM chain, leaf first) with keyPath. Port 0 lets the OS pick — recover it with port(). Binds exactly that; started under systemd socket activation for this process it errs naming inheritedOr.
TlsListener.handshakeWithin
fn TlsListener.handshakeWithin(self: &TlsListener, clientFd: i32, ms: i64): Result<TlsConn, NetError>The server handshake on clientFd, an accepted TCP connection this call takes over (closed on failure, owned by the TlsConn on success), finishing within ms (0 = no limit). acceptWithin's second half, apart so a concurrent server can accept on one task and handshake on the connection's own: a handshake on the accept task is one stalled client stopping every other accept. @unsafe: the caller vouches that clientFd is an accepted socket it owns and hands over here.
TlsListener.inheritedOr
fn TlsListener.inheritedOr(port: u16, certPath: &string, keyPath: &string): Result<TlsListener, NetError>The socket systemd socket activation passed this process, serving certPath with keyPath; or, when it was not started that way, a fresh bind of 0.0.0.0:port like bind. The TLS twin of TcpListener.inheritedOr; isInherited() says which happened.
TlsListener.isInherited
fn TlsListener.isInherited(self: &TlsListener): boolWhether this listener came from socket activation (inheritedOr) rather than a bind.
TlsListener.open
fn TlsListener.open(port: u16, certPath: &string, keyPath: &string, inherit: bool): Result<TlsListener, NetError>bind and inheritedOr: the inherited socket when inherit and there is one, else a fresh bind of 0.0.0.0:port; then the certificate chain and key. Use those two.
TlsListener.port
fn TlsListener.port(self: &TlsListener): i32The bound port — how to learn what the OS picked after bind(0). -1 if getsockname fails, mirroring getSockPort rather than reporting a plausible-looking port number.
TlsListener.releaseFd
fn TlsListener.releaseFd(self: &mut TlsListener): i32Hand the listening fd to a caller that will close it (std/https's accept loop does when draining); this listener then only frees the SSL_CTX on drop. @unsafe: the number is the caller's to close exactly once.