Module std::net

Networking as an effect: code reaches sockets only through a Net capability in its row, so its caller's executor decides how each operation waits. Net includes std::task::Tasks (so Clock) and std::fs::Fs: one executor parks sleepers, tasks, socket ops and file ops in one table, and code written with Tasks, with Clock or with Fs runs in a Net task unchanged. close is Fs's, the one close of every descriptor. Install Evented or Blocking in main (they need the root's Reactor, Sys and Threads); a test uses std::sim::net_world.

Serving: a function handed a listener &Fd cannot spawn a task that borrows it (the task may outlive the borrow). Spawn one acceptor task where the listener is a local, and move each accepted connection into a task of its own: spawn(move(c on_abort { close(c) }) || …).

A bare with Net is Net portable migrates cross, the bound under which a function runs under either executor and under the simulated world; a written bound replaces it.

Source: std/net.weir; committed interface: std/net.iface. Index

struct Addr

pub struct Addr: copy {
    pub ip: u32,
    pub port: u16,
}

An IPv4 socket address: where a listener binds, or where a connection goes. Every ip and port make one. Port 0 names no socket: there is no op to read back a port the system picked, so listen and connect answer Err(22) (EINVAL) for it.

std::net is TCP over IPv4 by address: IPv6, UDP, name resolution and TLS are outside it.

Fields:

impl Addr

method v4

pub fn v4(a: u8, b: u8, c: u8, d: u8, port: u16) -> Addr

a.b.c.d:port.

Committed interface (std/net.iface): the signature alone.

method loopback

pub fn loopback(port: u16) -> Addr

127.0.0.1:port: this host, reachable only from it.

Committed interface (std/net.iface): the signature alone.

method any

pub fn any(port: u16) -> Addr

0.0.0.0:port. A listener bound to it accepts connections to every address of this host, loopback included, so other hosts reach it; a connection to it goes to this host.

Committed interface (std/net.iface): the signature alone.

effect Net

pub effect Net : Tasks + Fs default portable migrates cross {
    once fn listen(addr: Addr, backlog: Int) -> Result<Fd, Int>;
    once fn accept(l: &Fd) -> Result<Fd, Int>;
    once fn connect(addr: Addr) -> Result<Fd, Int>;
    once fn recv(fd: &Fd, b: &mut [u8]) -> Result<usize, Int>;
    once fn send(fd: &Fd, b: &[u8]) -> Result<usize, Int>;
}

TCP sockets over IPv4, plus tasks, the clock and files; each op answers Err(errno) on failure and parks its task while it waits.

On the simulated network (std::sim::net_world, weir run, weir explore, weir test) there is one host and its addresses are loopback's, 127.0.0.0/8: a connection reaches the listener bound to its address, or to Addr::any when the address is a loopback one, and is refused (Err(111), ECONNREFUSED) when there is none, whatever the address. A listener may bind any address there; on a real host one the host does not have is Err(99) (EADDRNOTAVAIL).

op listen

once fn listen(addr: Addr, backlog: Int) -> Result<Fd, Int>;

Control kind once: the clause takes the continuation (cont k) and resumes or cancels it, so the perform is a suspension and an abort edge.

A socket listening on addr, with backlog pending connections. Err(98) (EADDRINUSE) when a listener already has the address: the same port, on the same IP or with either on Addr::any.

op accept

once fn accept(l: &Fd) -> Result<Fd, Int>;

Control kind once: the clause takes the continuation (cont k) and resumes or cancels it, so the perform is a suspension and an abort edge.

The next connection on listener l.

op connect

once fn connect(addr: Addr) -> Result<Fd, Int>;

Control kind once: the clause takes the continuation (cont k) and resumes or cancels it, so the perform is a suspension and an abort edge.

A connection to the listener at addr.

op recv

once fn recv(fd: &Fd, b: &mut [u8]) -> Result<usize, Int>;

Control kind once: the clause takes the continuation (cont k) and resumes or cancels it, so the perform is a suspension and an abort edge.

Reads into b: the count read, 0 at end of stream.

op send

once fn send(fd: &Fd, b: &[u8]) -> Result<usize, Int>;

Control kind once: the clause takes the continuation (cont k) and resumes or cancels it, so the perform is a suspension and an abort edge.

Writes from b: the count written, which may be short.

struct Socket

pub struct Socket {
    pub fd: Fd,
} drop with Net

A connection that closes itself: Socket { fd: c } owns c, &s.fd lends it to recv and send, and its drop performs close, so a task that ends, panics or is cancelled while it holds one closes the descriptor as it unwinds. The close's answer is dropped: a socket's close brings no data to the device (a send's failure shows at the send).

Fields:

handler Evented

pub handler Evented(
    s: Slots<Unit, once>,
    workers: usize,
    stopped: Atomic<Bool>,
): shared strict cross for Net with Reactor, Sys, th: Threads

The completion executor, for a server: many connections on few threads.

Each operation parks its task until the root's reactor completes it (send is tried first and parks only when the socket cannot take the bytes at once), so a connection costs a task frame, not a thread. Install it as with Evented(slots(), 4, atomic(false)) { … }: slots() is its table, workers threads run ready tasks and reap completions, and stopped must start unset. When the body and every task have ended, operations still in flight are cancelled and drained on the installing thread (with workers 0 every task runs there). now and sleep are in nanoseconds.

Stopping, as std::task::Pool does: once a task or the with body calls stop(), each task is cancelled at its next suspension. Every operation in flight is asked to cancel (one already complete wins: its task gets the result and is cancelled at its next operation), a task that performs an operation, sleeps, yields or parks from then on is cancelled from it, and one spawned from then on is cancelled before it starts (its move(… on_abort …) entries run). A cancelled task unwinds: its on_abort blocks and drop glue run, a Socket's closing its descriptor (close is never cancelled). A task already running, or ready, runs to its next suspension, and a task parked under a key no task wakes is cancelled once every other task has ended.

Handles Net, with clauses:

handler Blocking

pub handler Blocking(s: Slots<Unit, once>, stopped: Atomic<Bool>): shared strict cross for Net with
    Sys,
    th: Threads,

The blocking executor: each operation is one blocking system call on the calling thread.

A task waiting on the network pins its thread; 256 threads run spawned tasks, each to its end or its next yield_now or park, which frees the thread for another until the task is ready again. Install it as with Blocking(slots(), atomic(false)) { … } (stopped starts unset). now and sleep are in nanoseconds.

Stopping: stop(), from a task or the with body, cancels every network call waiting and every operation made from then on: accept, connect, recv and send answer Err(125) (ECANCELED) unless the kernel completed the call first, listen and the file operations answer it from then on (a file operation already in its system call finishes), so a task observes the stop at its current or next operation and runs its error path, and its Sockets close as it ends; a sleep ends early, close still runs, a task that yields or parks is cancelled from there, and a task spawned from then on is cancelled before it starts. A task parked under a key no task wakes is cancelled once every other task has ended.

Handles Net, with clauses: