extern unionstd.net.Address[src]

Fields

Error Sets

Error SetListenError[src]

Errors

anyerror means the error set is known only at runtime.

AccessDenied BindError

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.

AddressFamilyNotSupported SocketError

The implementation does not support the specified address family.

AddressInUse BindError

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).

AddressNotAvailable BindError

A nonexistent interface was requested or the requested address was not local.

AlreadyBound BindError
AlreadyConnected ListenError

Already connected

FileDescriptorNotASocket ListenError

The file descriptor sockfd does not refer to a socket.

FileNotFound BindError

A component in the directory prefix of the socket pathname does not exist.

InvalidProtocolOption SetSockOptError

The option is not supported by the protocol.

NameTooLong BindError

addr is too long.

NetworkSubsystemFailed BindError

The network subsystem has failed.

NotDir BindError

A component of the path prefix is not a directory.

OperationNotSupported ListenError

The socket is not of a type that supports the listen() operation.

PermissionDenied SocketError

Permission to create a socket of the specified type and/or pro‐tocol is denied.

ProcessFdQuotaExceeded SocketError

The per-process limit on the number of open file descriptors has been reached.

ProtocolFamilyNotAvailable SocketError

Unknown protocol, or protocol family not available.

ProtocolNotSupported SocketError

The protocol type or the specified protocol is not supported within this domain.

ReadOnlyFileSystem BindError

The socket inode would reside on a read-only filesystem.

SocketNotBound ListenError

Socket has not been bound yet

SocketTypeNotSupported SocketError

The socket type is not supported by the protocol.

SymLinkLoop BindError

Too many symbolic links were encountered in resolving addr.

SystemFdQuotaExceeded SocketError

The system-wide limit on the total number of open files has been reached.

SystemResources SocketError

Insufficient memory is available. The socket cannot be created until sufficient resources are freed.

TimeoutTooBig SetSockOptError

The send and receive timeout values are too big to fit into the timeout fields in the socket structure.

Unexpected UnexpectedError

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.

Source Code

Source code
pub const ListenError = posix.SocketError || posix.BindError || posix.ListenError ||
    posix.SetSockOptError || posix.GetSockNameError

Functions

FunctionparseIp[src]

pub fn parseIp(name: []const u8, port: u16) !Address

Parse the given IP address string into an Address value. It is recommended to use resolveIp instead, to handle IPv6 link-local unix addresses.

Parameters

name: []const u8
port: u16

Source Code

Source code
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;
}

FunctionresolveIp[src]

pub fn resolveIp(name: []const u8, port: u16) !Address

Parameters

name: []const u8
port: u16

Source Code

Source code
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;
}

FunctionparseExpectingFamily[src]

pub fn parseExpectingFamily(name: []const u8, family: posix.sa_family_t, port: u16) !Address

Parameters

name: []const u8
port: u16

Source Code

Source code
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,
    }
}

FunctionparseIp6[src]

pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address

Parameters

buf: []const u8
port: u16

Source Code

Source code
pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
    return .{ .in6 = try Ip6Address.parse(buf, port) };
}

FunctionresolveIp6[src]

pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address

Parameters

buf: []const u8
port: u16

Source Code

Source code
pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
    return .{ .in6 = try Ip6Address.resolve(buf, port) };
}

FunctionparseIp4[src]

pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address

Parameters

buf: []const u8
port: u16

Source Code

Source code
pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
    return .{ .in = try Ip4Address.parse(buf, port) };
}

FunctioninitIp4[src]

pub fn initIp4(addr: [4]u8, port: u16) Address

Parameters

addr: [4]u8
port: u16

Source Code

Source code
pub fn initIp4(addr: [4]u8, port: u16) Address {
    return .{ .in = Ip4Address.init(addr, port) };
}

FunctioninitIp6[src]

pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address

Parameters

addr: [16]u8
port: u16
flowinfo: u32
scope_id: u32

Source Code

Source code
pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
    return .{ .in6 = Ip6Address.init(addr, port, flowinfo, scope_id) };
}

FunctioninitUnix[src]

pub fn initUnix(path: []const u8) !Address

Parameters

path: []const u8

Source Code

Source code
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 };
}

FunctiongetPort[src]

pub fn getPort(self: Address) u16

Returns the port in native endian. Asserts that the address is ip4 or ip6.

Parameters

self: Address

Source Code

Source code
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,
    };
}

FunctionsetPort[src]

pub fn setPort(self: *Address, port: u16) void

port is native-endian. Asserts that the address is ip4 or ip6.

Parameters

self: *Address
port: u16

Source Code

Source code
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,
    }
}

FunctioninitPosix[src]

pub fn initPosix(addr: *align(4) const posix.sockaddr) Address

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.

Parameters

addr: *align(4) const posix.sockaddr

Source Code

Source code
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,
    }
}

Functionformat[src]

pub fn format( self: Address, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype, ) !void

Parameters

self: Address
fmt: []const u8

Source Code

Source code
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,
    }
}

Functioneql[src]

pub fn eql(a: Address, b: Address) bool

Parameters

Source Code

Source code
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);
}

FunctiongetOsSockLen[src]

pub fn getOsSockLen(self: Address) posix.socklen_t

Parameters

self: Address

Source Code

Source code
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,
    }
}

Functionlisten[src]

pub fn listen(address: Address, options: ListenOptions) ListenError!Server

The returned Server has an open stream.

Parameters

address: Address
options: ListenOptions

Source Code

Source code
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;
}

Source Code

Source code
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;
    }
}