anyerror means the error set is known only at runtime.
The address is protected, and the user is not the superuser. For UNIX domain sockets: Search permission is denied on a component of the path prefix.
The implementation does not support the specified address family.
The given address is already in use, or in the case of Internet domain sockets, The port number was specified as zero in the socket address structure, but, upon attempting to bind to an ephemeral port, it was determined that all port numbers in the ephemeral port range are currently in use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
A nonexistent interface was requested or the requested address was not local.
Already connected
The file descriptor sockfd does not refer to a socket.
A component in the directory prefix of the socket pathname does not exist.
The option is not supported by the protocol.
addr is too long.
The network subsystem has failed.
A component of the path prefix is not a directory.
The socket is not of a type that supports the listen() operation.
Permission to create a socket of the specified type and/or pro‐tocol is denied.
The per-process limit on the number of open file descriptors has been reached.
Unknown protocol, or protocol family not available.
The protocol type or the specified protocol is not supported within this domain.
The socket inode would reside on a read-only filesystem.
Socket has not been bound yet
The socket type is not supported by the protocol.
Too many symbolic links were encountered in resolving addr.
The system-wide limit on the total number of open files has been reached.
Insufficient memory is available. The socket cannot be created until sufficient resources are freed.
The send and receive timeout values are too big to fit into the timeout fields in the socket structure.
The Operating System returned an undocumented error code.
This error is in theory not possible, but it would be better to handle this error than to invoke undefined behavior.
When this error code is observed, it usually means the Zig Standard Library needs a small patch to add the error code to the error set for the respective function.
pub const ListenError = posix.SocketError || posix.BindError || posix.ListenError ||
posix.SetSockOptError || posix.GetSockNameErrorpub fn parseIp(name: []const u8, port: u16) !AddressParse the given IP address string into an Address value.
It is recommended to use resolveIp instead, to handle
IPv6 link-local unix addresses.
name: []const u8port: u16pub fn parseIp(name: []const u8, port: u16) !Address {
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.NonCanonical,
=> {},
}
if (parseIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.InvalidIpv4Mapping,
=> {},
}
return error.InvalidIPAddressFormat;
}pub fn resolveIp(name: []const u8, port: u16) !Addressname: []const u8port: u16pub fn resolveIp(name: []const u8, port: u16) !Address {
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.NonCanonical,
=> {},
}
if (resolveIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.InvalidIpv4Mapping,
=> {},
else => return err,
}
return error.InvalidIPAddressFormat;
}pub fn parseExpectingFamily(name: []const u8, family: posix.sa_family_t, port: u16) !Addresspub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Addressbuf: []const u8port: u16pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
return .{ .in6 = try Ip6Address.parse(buf, port) };
}pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Addressbuf: []const u8port: u16pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
return .{ .in6 = try Ip6Address.resolve(buf, port) };
}pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Addressbuf: []const u8port: u16pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
return .{ .in = try Ip4Address.parse(buf, port) };
}pub fn initIp4(addr: [4]u8, port: u16) Addressaddr: [4]u8port: u16pub fn initIp4(addr: [4]u8, port: u16) Address {
return .{ .in = Ip4Address.init(addr, port) };
}pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Addressaddr: [16]u8port: u16flowinfo: u32scope_id: u32pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
return .{ .in6 = Ip6Address.init(addr, port, flowinfo, scope_id) };
}pub fn initUnix(path: []const u8) !Addresspath: []const u8pub fn initUnix(path: []const u8) !Address {
var sock_addr = posix.sockaddr.un{
.family = posix.AF.UNIX,
.path = undefined,
};
// Add 1 to ensure a terminating 0 is present in the path array for maximum portability.
if (path.len + 1 > sock_addr.path.len) return error.NameTooLong;
@memset(&sock_addr.path, 0);
@memcpy(sock_addr.path[0..path.len], path);
return .{ .un = sock_addr };
}pub fn getPort(self: Address) u16Returns the port in native endian. Asserts that the address is ip4 or ip6.
self: Addresspub fn setPort(self: *Address, port: u16) voidport is native-endian.
Asserts that the address is ip4 or ip6.
self: *Addressport: u16Asserts that addr is an IP address.
This function will read past the end of the pointer, with a size depending
on the address family.
pub fn initPosix(addr: *align(4) const posix.sockaddr) Address {
switch (addr.family) {
posix.AF.INET => return Address{ .in = Ip4Address{ .sa = @as(*const posix.sockaddr.in, @ptrCast(addr)).* } },
posix.AF.INET6 => return Address{ .in6 = Ip6Address{ .sa = @as(*const posix.sockaddr.in6, @ptrCast(addr)).* } },
else => unreachable,
}
}pub fn format( self: Address, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype, ) !voidpub fn format(
self: Address,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
out_stream: anytype,
) !void {
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
switch (self.any.family) {
posix.AF.INET => try self.in.format(fmt, options, out_stream),
posix.AF.INET6 => try self.in6.format(fmt, options, out_stream),
posix.AF.UNIX => {
if (!has_unix_sockets) {
unreachable;
}
try std.fmt.format(out_stream, "{s}", .{std.mem.sliceTo(&self.un.path, 0)});
},
else => unreachable,
}
}self: Addresspub fn getOsSockLen(self: Address) posix.socklen_t {
switch (self.any.family) {
posix.AF.INET => return self.in.getOsSockLen(),
posix.AF.INET6 => return self.in6.getOsSockLen(),
posix.AF.UNIX => {
if (!has_unix_sockets) {
unreachable;
}
// Using the full length of the structure here is more portable than returning
// the number of bytes actually used by the currently stored path.
// This also is correct regardless if we are passing a socket address to the kernel
// (e.g. in bind, connect, sendto) since we ensure the path is 0 terminated in
// initUnix() or if we are receiving a socket address from the kernel and must
// provide the full buffer size (e.g. getsockname, getpeername, recvfrom, accept).
//
// To access the path, std.mem.sliceTo(&address.un.path, 0) should be used.
return @as(posix.socklen_t, @intCast(@sizeOf(posix.sockaddr.un)));
},
else => unreachable,
}
}pub fn listen(address: Address, options: ListenOptions) ListenError!ServerThe returned Server has an open stream.
address: Addressoptions: ListenOptionspub fn listen(address: Address, options: ListenOptions) ListenError!Server {
const nonblock: u32 = if (options.force_nonblocking) posix.SOCK.NONBLOCK else 0;
const sock_flags = posix.SOCK.STREAM | posix.SOCK.CLOEXEC | nonblock;
const proto: u32 = if (address.any.family == posix.AF.UNIX) 0 else posix.IPPROTO.TCP;
const sockfd = try posix.socket(address.any.family, sock_flags, proto);
var s: Server = .{
.listen_address = undefined,
.stream = .{ .handle = sockfd },
};
errdefer s.stream.close();
if (options.reuse_address or options.reuse_port) {
try posix.setsockopt(
sockfd,
posix.SOL.SOCKET,
posix.SO.REUSEADDR,
&mem.toBytes(@as(c_int, 1)),
);
if (@hasDecl(posix.SO, "REUSEPORT") and address.any.family != posix.AF.UNIX) {
try posix.setsockopt(
sockfd,
posix.SOL.SOCKET,
posix.SO.REUSEPORT,
&mem.toBytes(@as(c_int, 1)),
);
}
}
var socklen = address.getOsSockLen();
try posix.bind(sockfd, &address.any, socklen);
try posix.listen(sockfd, options.kernel_backlog);
try posix.getsockname(sockfd, &s.listen_address.any, &socklen);
return s;
}pub const Address = extern union {
any: posix.sockaddr,
in: Ip4Address,
in6: Ip6Address,
un: if (has_unix_sockets) posix.sockaddr.un else void,
/// Parse the given IP address string into an Address value.
/// It is recommended to use `resolveIp` instead, to handle
/// IPv6 link-local unix addresses.
pub fn parseIp(name: []const u8, port: u16) !Address {
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.NonCanonical,
=> {},
}
if (parseIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.InvalidIpv4Mapping,
=> {},
}
return error.InvalidIPAddressFormat;
}
pub fn resolveIp(name: []const u8, port: u16) !Address {
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.NonCanonical,
=> {},
}
if (resolveIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
error.Overflow,
error.InvalidEnd,
error.InvalidCharacter,
error.Incomplete,
error.InvalidIpv4Mapping,
=> {},
else => return err,
}
return error.InvalidIPAddressFormat;
}
pub fn parseExpectingFamily(name: []const u8, family: posix.sa_family_t, port: u16) !Address {
switch (family) {
posix.AF.INET => return parseIp4(name, port),
posix.AF.INET6 => return parseIp6(name, port),
posix.AF.UNSPEC => return parseIp(name, port),
else => unreachable,
}
}
pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
return .{ .in6 = try Ip6Address.parse(buf, port) };
}
pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
return .{ .in6 = try Ip6Address.resolve(buf, port) };
}
pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
return .{ .in = try Ip4Address.parse(buf, port) };
}
pub fn initIp4(addr: [4]u8, port: u16) Address {
return .{ .in = Ip4Address.init(addr, port) };
}
pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
return .{ .in6 = Ip6Address.init(addr, port, flowinfo, scope_id) };
}
pub fn initUnix(path: []const u8) !Address {
var sock_addr = posix.sockaddr.un{
.family = posix.AF.UNIX,
.path = undefined,
};
// Add 1 to ensure a terminating 0 is present in the path array for maximum portability.
if (path.len + 1 > sock_addr.path.len) return error.NameTooLong;
@memset(&sock_addr.path, 0);
@memcpy(sock_addr.path[0..path.len], path);
return .{ .un = sock_addr };
}
/// Returns the port in native endian.
/// Asserts that the address is ip4 or ip6.
pub fn getPort(self: Address) u16 {
return switch (self.any.family) {
posix.AF.INET => self.in.getPort(),
posix.AF.INET6 => self.in6.getPort(),
else => unreachable,
};
}
/// `port` is native-endian.
/// Asserts that the address is ip4 or ip6.
pub fn setPort(self: *Address, port: u16) void {
switch (self.any.family) {
posix.AF.INET => self.in.setPort(port),
posix.AF.INET6 => self.in6.setPort(port),
else => unreachable,
}
}
/// Asserts that `addr` is an IP address.
/// This function will read past the end of the pointer, with a size depending
/// on the address family.
pub fn initPosix(addr: *align(4) const posix.sockaddr) Address {
switch (addr.family) {
posix.AF.INET => return Address{ .in = Ip4Address{ .sa = @as(*const posix.sockaddr.in, @ptrCast(addr)).* } },
posix.AF.INET6 => return Address{ .in6 = Ip6Address{ .sa = @as(*const posix.sockaddr.in6, @ptrCast(addr)).* } },
else => unreachable,
}
}
pub fn format(
self: Address,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
out_stream: anytype,
) !void {
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
switch (self.any.family) {
posix.AF.INET => try self.in.format(fmt, options, out_stream),
posix.AF.INET6 => try self.in6.format(fmt, options, out_stream),
posix.AF.UNIX => {
if (!has_unix_sockets) {
unreachable;
}
try std.fmt.format(out_stream, "{s}", .{std.mem.sliceTo(&self.un.path, 0)});
},
else => unreachable,
}
}
pub fn eql(a: Address, b: Address) bool {
const a_bytes = @as([*]const u8, @ptrCast(&a.any))[0..a.getOsSockLen()];
const b_bytes = @as([*]const u8, @ptrCast(&b.any))[0..b.getOsSockLen()];
return mem.eql(u8, a_bytes, b_bytes);
}
pub fn getOsSockLen(self: Address) posix.socklen_t {
switch (self.any.family) {
posix.AF.INET => return self.in.getOsSockLen(),
posix.AF.INET6 => return self.in6.getOsSockLen(),
posix.AF.UNIX => {
if (!has_unix_sockets) {
unreachable;
}
// Using the full length of the structure here is more portable than returning
// the number of bytes actually used by the currently stored path.
// This also is correct regardless if we are passing a socket address to the kernel
// (e.g. in bind, connect, sendto) since we ensure the path is 0 terminated in
// initUnix() or if we are receiving a socket address from the kernel and must
// provide the full buffer size (e.g. getsockname, getpeername, recvfrom, accept).
//
// To access the path, std.mem.sliceTo(&address.un.path, 0) should be used.
return @as(posix.socklen_t, @intCast(@sizeOf(posix.sockaddr.un)));
},
else => unreachable,
}
}
pub const ListenError = posix.SocketError || posix.BindError || posix.ListenError ||
posix.SetSockOptError || posix.GetSockNameError;
pub const ListenOptions = struct {
/// How many connections the kernel will accept on the application's behalf.
/// If more than this many connections pool in the kernel, clients will start
/// seeing "Connection refused".
kernel_backlog: u31 = 128,
/// Sets SO_REUSEADDR and SO_REUSEPORT on POSIX.
/// Sets SO_REUSEADDR on Windows, which is roughly equivalent.
reuse_address: bool = false,
/// Deprecated. Does the same thing as reuse_address.
reuse_port: bool = false,
force_nonblocking: bool = false,
};
/// The returned `Server` has an open `stream`.
pub fn listen(address: Address, options: ListenOptions) ListenError!Server {
const nonblock: u32 = if (options.force_nonblocking) posix.SOCK.NONBLOCK else 0;
const sock_flags = posix.SOCK.STREAM | posix.SOCK.CLOEXEC | nonblock;
const proto: u32 = if (address.any.family == posix.AF.UNIX) 0 else posix.IPPROTO.TCP;
const sockfd = try posix.socket(address.any.family, sock_flags, proto);
var s: Server = .{
.listen_address = undefined,
.stream = .{ .handle = sockfd },
};
errdefer s.stream.close();
if (options.reuse_address or options.reuse_port) {
try posix.setsockopt(
sockfd,
posix.SOL.SOCKET,
posix.SO.REUSEADDR,
&mem.toBytes(@as(c_int, 1)),
);
if (@hasDecl(posix.SO, "REUSEPORT") and address.any.family != posix.AF.UNIX) {
try posix.setsockopt(
sockfd,
posix.SOL.SOCKET,
posix.SO.REUSEPORT,
&mem.toBytes(@as(c_int, 1)),
);
}
}
var socklen = address.getOsSockLen();
try posix.bind(sockfd, &address.any, socklen);
try posix.listen(sockfd, options.kernel_backlog);
try posix.getsockname(sockfd, &s.listen_address.any, &socklen);
return s;
}
}