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: An IPv4 socket address: where a listener binds, or where a connection goes. Everyipandportmake one. Port 0 names no socket: there is no op to read back a port the system picked, solistenandconnectanswerErr(22)(EINVAL) for it. - effect
Net: TCP sockets over IPv4, plus tasks, the clock and files; each op answersErr(errno)on failure and parks its task while it waits. - struct
Socket: A connection that closes itself:Socket { fd: c }ownsc,&s.fdlends it torecvandsend, and its drop performsclose, 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). - handler
Evented: The completion executor, for a server: many connections on few threads. - handler
Blocking: The blocking executor: each operation is one blocking system call on the calling thread.
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:
pub ip: u32: The address as one number, its first octet the most significant byte:127.0.0.1is0x7f000001.pub port: u16
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:
fn now()once fn sleep(d: Int) cont kfn spawn(f: fn())fn stop()once fn yield_now() cont ktail fn preempt()fn waker()once fn park(w: Waker) cont kfn wake(w: Waker)once fn listen(addr: Addr, backlog: Int) cont konce fn accept(l: &Fd) cont konce fn connect(addr: Addr) cont konce fn recv(fd: &Fd, b: &mut [u8]) cont konce fn send(fd: &Fd, b: &[u8]) cont konce fn open(dir: &Fd, path: &[u8], flags: Int) cont konce fn read_at(f: &Fd, b: &mut [u8], off: usize) cont konce fn write_at(f: &Fd, b: &[u8], off: usize) cont konce fn sync(f: &Fd) cont konce fn size(f: &Fd) cont konce fn mkdir(dir: &Fd, path: &[u8]) cont konce fn remove(dir: &Fd, path: &[u8]) cont konce fn rename(dir: &Fd, from: &[u8], to: &[u8]) cont konce fn list(dir: &Fd, b: &mut [u8], at: usize) cont klinear fn close(fd: Fd) cont k
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:
fn now()tail fn sleep(d: Int)fn spawn(f: fn())fn stop()once fn yield_now() cont ktail fn preempt()fn waker()once fn park(w: Waker) cont kfn wake(w: Waker)tail fn listen(addr: Addr, backlog: Int)tail fn accept(l: &Fd)tail fn connect(addr: Addr)tail fn recv(fd: &Fd, b: &mut [u8])tail fn send(fd: &Fd, b: &[u8])tail fn open(dir: &Fd, path: &[u8], flags: Int)tail fn read_at(f: &Fd, b: &mut [u8], off: usize)tail fn write_at(f: &Fd, b: &[u8], off: usize)tail fn sync(f: &Fd)tail fn size(f: &Fd)tail fn mkdir(dir: &Fd, path: &[u8])tail fn remove(dir: &Fd, path: &[u8])tail fn rename(dir: &Fd, from: &[u8], to: &[u8])tail fn list(dir: &Fd, b: &mut [u8], at: usize)tail fn close(fd: Fd)