Dista · API

dista.socket

IPv4 TCP and process control over libc.

Just enough of socket(2) and friends for dista's processes: listeners on loopback or on every interface, streams to a host name or to loopback, the non-blocking reads and writes the head's event loop uses, poll, and fork/waitpid/_exit to start and reap local processes. macOS and Linux differ in sockaddr_in's first byte, in addrinfo's field order, in the SOL_SOCKET, MSG_DONTWAIT and EAGAIN constants, and in how a write to a closed peer is kept from raising SIGPIPE; platform_map picks the right value for each.

Structs

Stream

struct Stream

A connected TCP socket. It's non-blocking, but write_all and read_into wait for it, so to its users it blocks; the head's loop uses send_some and recv_some, which don't. Closes itself when dropped.

Implements Movable

Fields
fd: c_int

__init__

def __init__(out self, fd: Int32)

__deinit__

def __deinit__(deinit self)

connect

def connect(port: Int) -> Self

Connects to 127.0.0.1:port.

def connect(host: String, port: Int) -> Self

Connects to host:port; host is a name or a dotted quad.

def connect(ip: Array[UInt8, Int(4)], port: Int) -> Self

Connects to ip:port.

local_ip

def local_ip(self) -> Array[UInt8, Int(4)]

The local IPv4 address this connection goes out from.

write_all

def write_all(self, data: Span[UInt8])

Writes every byte of data.

read_into

def read_into(self, buf: Pointer[UInt8], size: Int) -> Int

Reads exactly size bytes into buf.

Returns size, or 0 when the peer closed before sending anything. Raises if the peer closes partway through.

close

def close(mut self)

Listener

struct Listener

A TCP listener. Closes itself when dropped.

Implements Movable

Fields
fd: c_int
port: Int

__init__

def __init__(out self, port: Int = Int(0), any_interface: Bool = False, backlog: Int = Int(128))

Binds and starts listening.

Args
port: The port, or 0 for one the OS picks.
any_interface: Listen on every interface instead of loopback.
backlog: How many connections may wait to be accepted.

__deinit__

def __deinit__(deinit self)

accept

def accept(self) -> Stream

Waits for the next connection.

close

def close(mut self)

Functions

resolve_ipv4

def resolve_ipv4(host: String) -> Array[UInt8, Int(4)]

The first IPv4 address of host, a name or a dotted quad.

send_some

def send_some(fd: Int32, data: Pointer[UInt8], size: Int) -> Int

Sends what the socket takes without blocking. Returns the bytes sent.

recv_some

def recv_some(fd: Int32, buf: Pointer[UInt8], size: Int) -> Int

Reads what has arrived, without blocking.

Returns the bytes read, 0 at end of stream, or -1 if nothing is waiting.

fcntl

def fcntl(fd: Int32, cmd: Int32, arg: Int32) -> c_int

fcntl(2) with one int argument: the only declaration of it in dista, since two with different signatures don't link.

set_nonblocking

def set_nonblocking(fd: Int32) -> Bool

Makes fd non-blocking; whether that worked.

wall_ns

def wall_ns() -> UInt64

Nanoseconds since the epoch, from CLOCK_REALTIME.

The timeline stamps tasks on the head and on workers with this, so the stamps compare across processes and, NTP permitting, machines; a monotonic clock only compares within one host.

stream_pair

def stream_pair() -> List[Stream]

Two connected local stream sockets, for tests and fuzzing.

poll

def poll(fds: List[Int32], events: List[Int16], timeout_ms: Int = Int(-1)) -> List[Int16]

Waits for any of events[i] on fds[i], or until timeout_ms passes.

Returns each descriptor's revents. A timeout of -1 waits indefinitely.

poll_readable

def poll_readable(fds: List[Int32], timeout_ms: Int = Int(-1)) -> List[Bool]

Waits until at least one of fds is readable, or timeout_ms passes.

A closed or failed socket counts as readable, so the read that follows reports it. A timeout of -1 waits indefinitely.

fork

def fork() -> Int

Forks the process. Returns 0 in the child, the child's pid in the parent.

wait_child

def wait_child(pid: Int) -> Int

Waits for child pid to exit and returns its raw wait status.

exit_now

def exit_now(code: Int)

Ends the process immediately, without running atexit handlers.

A forked worker leaves through here, so it never returns into the driver's main or flushes the driver's buffered output a second time.

addr_key

def addr_key(ip: Array[UInt8, Int(4)], port: Int) -> String

Aliases

comptime AF_INET = Int32(2)
comptime SOCK_STREAM = Int32(1)
comptime SOL_SOCKET = SIMD(platform_map[Optional(String("SOL_SOCKET")), linux=Optional(Int(1)), macos=Optional(Int(65535))]())
comptime SO_REUSEADDR = SIMD(platform_map[Optional(String("SO_REUSEADDR")), linux=Optional(Int(2)), macos=Optional(Int(4))]())
comptime SO_NOSIGPIPE = SIMD(platform_map[Optional(String("SO_NOSIGPIPE")), linux=Optional(Int(0)), macos=Optional(Int(4130))]())
comptime MSG_NOSIGNAL = SIMD(platform_map[Optional(String("MSG_NOSIGNAL")), linux=Optional(Int(16384)), macos=Optional(Int(0))]())
comptime EINTR = Int32(4)
comptime IPPROTO_TCP = Int32(6)
comptime TCP_NODELAY = Int32(1)
comptime SOCKADDR_IN_SIZE = 16
comptime EAGAIN = SIMD(platform_map[Optional(String("EAGAIN")), linux=Optional(Int(11)), macos=Optional(Int(35))]())
comptime F_GETFL = Int32(3)
comptime F_SETFL = Int32(4)
comptime O_NONBLOCK = SIMD(platform_map[Optional(String("O_NONBLOCK")), linux=Optional(Int(2048)), macos=Optional(Int(4))]())
comptime MSG_DONTWAIT = SIMD(platform_map[Optional(String("MSG_DONTWAIT")), linux=Optional(Int(64)), macos=Optional(Int(128))]())
comptime ADDRINFO_SIZE = 48
comptime ADDRINFO_FAMILY_OFF = 4
comptime ADDRINFO_SOCKTYPE_OFF = 8
comptime ADDRINFO_ADDR_OFF = platform_map[Optional(String("AI_ADDR_OFF")), linux=Optional(Int(24)), macos=Optional(Int(32))]()
comptime POLLIN = Int16(1)
comptime POLLOUT = Int16(4)
comptime POLLERR = Int16(8)
comptime POLLHUP = Int16(16)
comptime POLLFD_SIZE = 8