master
   1const builtin = @import("builtin");
   2const native_os = builtin.os.tag;
   3const std = @import("../std.zig");
   4const Io = std.Io;
   5const assert = std.debug.assert;
   6
   7pub const HostName = @import("net/HostName.zig");
   8
   9/// Source of truth: Internet Assigned Numbers Authority (IANA)
  10pub const Protocol = enum(u32) {
  11    hopopts = 0,
  12    icmp = 1,
  13    igmp = 2,
  14    ipip = 4,
  15    tcp = 6,
  16    egp = 8,
  17    pup = 12,
  18    udp = 17,
  19    idp = 22,
  20    tp = 29,
  21    dccp = 33,
  22    ipv6 = 41,
  23    routing = 43,
  24    fragment = 44,
  25    rsvp = 46,
  26    gre = 47,
  27    esp = 50,
  28    ah = 51,
  29    icmpv6 = 58,
  30    none = 59,
  31    dstopts = 60,
  32    mtp = 92,
  33    beetph = 94,
  34    encap = 98,
  35    pim = 103,
  36    comp = 108,
  37    sctp = 132,
  38    mh = 135,
  39    udplite = 136,
  40    mpls = 137,
  41    ethernet = 143,
  42    raw = 255,
  43    mptcp = 262,
  44};
  45
  46/// Windows 10 added support for unix sockets in build 17063, redstone 4 is the
  47/// first release to support them.
  48pub const has_unix_sockets = switch (native_os) {
  49    .windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false,
  50    .wasi => false,
  51    else => true,
  52};
  53
  54pub const default_kernel_backlog = 128;
  55
  56pub const IpAddress = union(enum) {
  57    ip4: Ip4Address,
  58    ip6: Ip6Address,
  59
  60    pub const Family = @typeInfo(IpAddress).@"union".tag_type.?;
  61
  62    pub const ParseLiteralError = error{ InvalidAddress, InvalidPort };
  63
  64    /// Parse an IP address which may include a port.
  65    ///
  66    /// For IPv4, this is written `address:port`.
  67    ///
  68    /// For IPv6, RFC 3986 defines this as an "IP literal", and the port is
  69    /// differentiated from the address by surrounding the address part in
  70    /// brackets "[addr]:port". Even if the port is not given, the brackets are
  71    /// mandatory.
  72    pub fn parseLiteral(text: []const u8) ParseLiteralError!IpAddress {
  73        if (text.len == 0) return error.InvalidAddress;
  74        if (text[0] == '[') {
  75            const addr_end = std.mem.findScalar(u8, text, ']') orelse
  76                return error.InvalidAddress;
  77            const addr_text = text[1..addr_end];
  78            const port: u16 = p: {
  79                if (addr_end == text.len - 1) break :p 0;
  80                if (text[addr_end + 1] != ':') return error.InvalidAddress;
  81                break :p std.fmt.parseInt(u16, text[addr_end + 2 ..], 10) catch return error.InvalidPort;
  82            };
  83            return parseIp6(addr_text, port) catch error.InvalidAddress;
  84        }
  85        if (std.mem.findScalar(u8, text, ':')) |i| {
  86            const addr = Ip4Address.parse(text[0..i], 0) catch return error.InvalidAddress;
  87            return .{ .ip4 = .{
  88                .bytes = addr.bytes,
  89                .port = std.fmt.parseInt(u16, text[i + 1 ..], 10) catch return error.InvalidPort,
  90            } };
  91        }
  92        return parseIp4(text, 0) catch error.InvalidAddress;
  93    }
  94
  95    /// Parse the given IP address string into an `IpAddress` value.
  96    ///
  97    /// This is a pure function but it cannot handle IPv6 addresses that have
  98    /// scope ids ("%foo" at the end). To also handle those, `resolve` must be
  99    /// called instead.
 100    pub fn parse(text: []const u8, port: u16) !IpAddress {
 101        if (parseIp4(text, port)) |ip4| return ip4 else |err| switch (err) {
 102            error.Overflow,
 103            error.InvalidEnd,
 104            error.InvalidCharacter,
 105            error.Incomplete,
 106            error.NonCanonical,
 107            => {},
 108        }
 109
 110        return parseIp6(text, port);
 111    }
 112
 113    pub fn parseIp4(text: []const u8, port: u16) Ip4Address.ParseError!IpAddress {
 114        return .{ .ip4 = try Ip4Address.parse(text, port) };
 115    }
 116
 117    /// This is a pure function but it cannot handle IPv6 addresses that have
 118    /// scope ids ("%foo" at the end). To also handle those, `resolveIp6` must be
 119    /// called instead.
 120    pub fn parseIp6(text: []const u8, port: u16) Ip6Address.ParseError!IpAddress {
 121        return .{ .ip6 = try Ip6Address.parse(text, port) };
 122    }
 123
 124    /// This function requires an `Io` parameter because it must query the operating
 125    /// system to convert interface name to index. For example, in
 126    /// "fe80::e0e:76ff:fed4:cf22%eno1", "eno1" must be resolved to an index by
 127    /// creating a socket and then using an `ioctl` syscall.
 128    ///
 129    /// For a pure function that cannot handle scopes, see `parse`.
 130    pub fn resolve(io: Io, text: []const u8, port: u16) !IpAddress {
 131        if (parseIp4(text, port)) |ip4| return ip4 else |err| switch (err) {
 132            error.Overflow,
 133            error.InvalidEnd,
 134            error.InvalidCharacter,
 135            error.Incomplete,
 136            error.NonCanonical,
 137            => {},
 138        }
 139
 140        return resolveIp6(io, text, port);
 141    }
 142
 143    pub fn resolveIp6(io: Io, text: []const u8, port: u16) Ip6Address.ResolveError!IpAddress {
 144        return .{ .ip6 = try Ip6Address.resolve(io, text, port) };
 145    }
 146
 147    /// Returns the port in native endian.
 148    pub fn getPort(a: IpAddress) u16 {
 149        return switch (a) {
 150            inline .ip4, .ip6 => |x| x.port,
 151        };
 152    }
 153
 154    /// `port` is native-endian.
 155    pub fn setPort(a: *IpAddress, port: u16) void {
 156        switch (a) {
 157            inline .ip4, .ip6 => |*x| x.port = port,
 158        }
 159    }
 160
 161    /// Includes the optional scope ("%foo" at the end) in IPv6 addresses.
 162    ///
 163    /// See `format` for an alternative that omits scopes and does
 164    /// not require an `Io` parameter.
 165    pub fn formatResolved(a: IpAddress, io: Io, w: *Io.Writer) Ip6Address.FormatError!void {
 166        switch (a) {
 167            .ip4 => |x| return x.format(w),
 168            .ip6 => |x| return x.formatResolved(io, w),
 169        }
 170    }
 171
 172    /// See `formatResolved` for an alternative that additionally prints the optional
 173    /// scope at the end of IPv6 addresses and requires an `Io` parameter.
 174    pub fn format(a: IpAddress, w: *Io.Writer) Io.Writer.Error!void {
 175        switch (a) {
 176            inline .ip4, .ip6 => |x| return x.format(w),
 177        }
 178    }
 179
 180    pub fn eql(a: *const IpAddress, b: *const IpAddress) bool {
 181        return switch (a.*) {
 182            .ip4 => |a_ip4| switch (b.*) {
 183                .ip4 => |b_ip4| a_ip4.eql(b_ip4),
 184                else => false,
 185            },
 186            .ip6 => |a_ip6| switch (b.*) {
 187                .ip6 => |b_ip6| a_ip6.eql(b_ip6),
 188                else => false,
 189            },
 190        };
 191    }
 192
 193    pub const ListenError = error{
 194        /// The address is already taken. Can occur when bound port is 0 but
 195        /// all ephemeral ports are already in use.
 196        AddressInUse,
 197        /// A nonexistent interface was requested or the requested address was not local.
 198        AddressUnavailable,
 199        /// The local network interface used to reach the destination is offline.
 200        NetworkDown,
 201        /// Insufficient memory or other resource internal to the operating system.
 202        SystemResources,
 203        /// Per-process limit on the number of open file descriptors has been reached.
 204        ProcessFdQuotaExceeded,
 205        /// System-wide limit on the total number of open files has been reached.
 206        SystemFdQuotaExceeded,
 207        /// The requested address family (IPv4 or IPv6) is not supported by the operating system.
 208        AddressFamilyUnsupported,
 209        ProtocolUnsupportedBySystem,
 210        ProtocolUnsupportedByAddressFamily,
 211        SocketModeUnsupported,
 212        /// One of the `ListenOptions` is not supported by the Io
 213        /// implementation.
 214        OptionUnsupported,
 215    } || Io.UnexpectedError || Io.Cancelable;
 216
 217    pub const ListenOptions = struct {
 218        /// How many connections the kernel will accept on the application's behalf.
 219        /// If more than this many connections pool in the kernel, clients will start
 220        /// seeing "Connection refused".
 221        kernel_backlog: u31 = default_kernel_backlog,
 222        /// Sets SO_REUSEADDR and SO_REUSEPORT on POSIX.
 223        /// Sets SO_REUSEADDR on Windows, which is roughly equivalent.
 224        reuse_address: bool = false,
 225        /// Only connection-oriented modes may be used here, which includes:
 226        /// * `Socket.Mode.stream`
 227        /// * `Socket.Mode.seqpacket`
 228        mode: Socket.Mode = .stream,
 229        /// Only connection-oriented protocols may be used here, which includes:
 230        /// * `Protocol.tcp`
 231        /// * `Protocol.tp`
 232        /// * `Protocol.dccp`
 233        /// * `Protocol.sctp`
 234        protocol: Protocol = .tcp,
 235    };
 236
 237    /// Waits for a TCP connection. When using this API, `bind` does not need
 238    /// to be called. The returned `Server` has an open `stream`.
 239    pub fn listen(address: IpAddress, io: Io, options: ListenOptions) ListenError!Server {
 240        return io.vtable.netListenIp(io.userdata, address, options);
 241    }
 242
 243    pub const BindError = error{
 244        /// The address is already taken. Can occur when bound port is 0 but
 245        /// all ephemeral ports are already in use.
 246        AddressInUse,
 247        /// A nonexistent interface was requested or the requested address was not local.
 248        AddressUnavailable,
 249        /// The address is not valid for the address family of socket.
 250        AddressFamilyUnsupported,
 251        /// Insufficient memory or other resource internal to the operating system.
 252        SystemResources,
 253        /// The local network interface used to reach the destination is offline.
 254        NetworkDown,
 255        ProtocolUnsupportedBySystem,
 256        ProtocolUnsupportedByAddressFamily,
 257        /// Per-process limit on the number of open file descriptors has been reached.
 258        ProcessFdQuotaExceeded,
 259        /// System-wide limit on the total number of open files has been reached.
 260        SystemFdQuotaExceeded,
 261        SocketModeUnsupported,
 262        /// One of the `BindOptions` is not supported by the Io
 263        /// implementation.
 264        OptionUnsupported,
 265    } || Io.UnexpectedError || Io.Cancelable;
 266
 267    pub const BindOptions = struct {
 268        /// The socket is restricted to sending and receiving IPv6 packets only.
 269        /// In this case, an IPv4 and an IPv6 application can bind to a single port
 270        /// at the same time.
 271        ip6_only: bool = false,
 272        mode: Socket.Mode,
 273        protocol: ?Protocol = null,
 274    };
 275
 276    /// Associates an address with a `Socket` which can be used to receive UDP
 277    /// packets and other kinds of non-streaming messages. See `listen` for a
 278    /// streaming alternative.
 279    ///
 280    /// One bound `Socket` can be used to receive messages from multiple
 281    /// different addresses.
 282    pub fn bind(address: *const IpAddress, io: Io, options: BindOptions) BindError!Socket {
 283        return io.vtable.netBindIp(io.userdata, address, options);
 284    }
 285
 286    pub const ConnectError = error{
 287        AddressUnavailable,
 288        AddressFamilyUnsupported,
 289        /// Insufficient memory or other resource internal to the operating system.
 290        SystemResources,
 291        ConnectionPending,
 292        ConnectionRefused,
 293        ConnectionResetByPeer,
 294        HostUnreachable,
 295        NetworkUnreachable,
 296        Timeout,
 297        /// One of the `ConnectOptions` is not supported by the Io
 298        /// implementation.
 299        OptionUnsupported,
 300        /// Per-process limit on the number of open file descriptors has been reached.
 301        ProcessFdQuotaExceeded,
 302        /// System-wide limit on the total number of open files has been reached.
 303        SystemFdQuotaExceeded,
 304        ProtocolUnsupportedBySystem,
 305        ProtocolUnsupportedByAddressFamily,
 306        SocketModeUnsupported,
 307        /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
 308        /// the connection request failed because of a local firewall rule.
 309        AccessDenied,
 310        /// Non-blocking was requested and the operation cannot return immediately.
 311        WouldBlock,
 312        NetworkDown,
 313    } || Io.Timeout.Error || Io.UnexpectedError || Io.Cancelable;
 314
 315    pub const ConnectOptions = struct {
 316        mode: Socket.Mode,
 317        protocol: ?Protocol = null,
 318        timeout: Io.Timeout = .none,
 319    };
 320
 321    /// Initiates a connection-oriented network stream.
 322    pub fn connect(address: IpAddress, io: Io, options: ConnectOptions) ConnectError!Stream {
 323        return io.vtable.netConnectIp(io.userdata, &address, options);
 324    }
 325};
 326
 327/// An IPv4 address in binary memory layout.
 328pub const Ip4Address = struct {
 329    bytes: [4]u8,
 330    port: u16,
 331
 332    pub fn loopback(port: u16) Ip4Address {
 333        return .{
 334            .bytes = .{ 127, 0, 0, 1 },
 335            .port = port,
 336        };
 337    }
 338
 339    pub fn unspecified(port: u16) Ip4Address {
 340        return .{
 341            .bytes = .{ 0, 0, 0, 0 },
 342            .port = port,
 343        };
 344    }
 345
 346    pub const ParseError = error{
 347        Overflow,
 348        InvalidEnd,
 349        InvalidCharacter,
 350        Incomplete,
 351        NonCanonical,
 352    };
 353
 354    pub fn parse(buffer: []const u8, port: u16) ParseError!Ip4Address {
 355        var bytes: [4]u8 = @splat(0);
 356        var index: u8 = 0;
 357        var saw_any_digits = false;
 358        var has_zero_prefix = false;
 359        for (buffer) |c| switch (c) {
 360            '.' => {
 361                if (!saw_any_digits) return error.InvalidCharacter;
 362                if (index == 3) return error.InvalidEnd;
 363                index += 1;
 364                saw_any_digits = false;
 365                has_zero_prefix = false;
 366            },
 367            '0'...'9' => {
 368                if (c == '0' and !saw_any_digits) {
 369                    has_zero_prefix = true;
 370                } else if (has_zero_prefix) {
 371                    return error.NonCanonical;
 372                }
 373                saw_any_digits = true;
 374                bytes[index] = try std.math.mul(u8, bytes[index], 10);
 375                bytes[index] = try std.math.add(u8, bytes[index], c - '0');
 376            },
 377            else => return error.InvalidCharacter,
 378        };
 379        if (index == 3 and saw_any_digits) return .{
 380            .bytes = bytes,
 381            .port = port,
 382        };
 383        return error.Incomplete;
 384    }
 385
 386    pub fn format(a: Ip4Address, w: *Io.Writer) Io.Writer.Error!void {
 387        const bytes = &a.bytes;
 388        try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], a.port });
 389    }
 390
 391    pub fn eql(a: Ip4Address, b: Ip4Address) bool {
 392        const a_int: u32 = @bitCast(a.bytes);
 393        const b_int: u32 = @bitCast(b.bytes);
 394        return a.port == b.port and a_int == b_int;
 395    }
 396};
 397
 398/// An IPv6 address in binary memory layout.
 399pub const Ip6Address = struct {
 400    /// Native endian
 401    port: u16,
 402    /// Big endian
 403    bytes: [16]u8,
 404    flow: u32 = 0,
 405    interface: Interface = .none,
 406
 407    pub const Policy = struct {
 408        addr: [16]u8,
 409        len: u8,
 410        mask: u8,
 411        prec: u8,
 412        label: u8,
 413    };
 414
 415    pub fn loopback(port: u16) Ip6Address {
 416        return .{
 417            .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 418            .port = port,
 419        };
 420    }
 421
 422    pub fn unspecified(port: u16) Ip6Address {
 423        return .{
 424            .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 425            .port = port,
 426        };
 427    }
 428
 429    /// Constructs an IPv4-mapped IPv6 address.
 430    pub fn fromIp4(ip4: Ip4Address) Ip6Address {
 431        const b = &ip4.bytes;
 432        return .{
 433            .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, b[0], b[1], b[2], b[3] },
 434            .port = ip4.port,
 435        };
 436    }
 437
 438    /// Given an `IpAddress`, converts it to an `Ip6Address` directly, or via
 439    /// constructing an IPv4-mapped IPv6 address.
 440    pub fn fromAny(addr: IpAddress) Ip6Address {
 441        return switch (addr) {
 442            .ip4 => |ip4| fromIp4(ip4),
 443            .ip6 => |ip6| ip6,
 444        };
 445    }
 446
 447    /// An IPv6 address but with `Interface` as a name rather than index.
 448    pub const Unresolved = struct {
 449        /// Big endian
 450        bytes: [16]u8,
 451        /// Has not been checked to be a valid native interface name.
 452        /// Externally managed memory.
 453        interface_name: ?[]const u8,
 454
 455        pub const Parsed = union(enum) {
 456            success: Unresolved,
 457            invalid_byte: usize,
 458            incomplete,
 459            junk_after_end: usize,
 460            interface_name_oversized: usize,
 461            invalid_ip4_mapping: usize,
 462            overflow: usize,
 463        };
 464
 465        pub fn parse(text: []const u8) Parsed {
 466            if (text.len < 2) return .incomplete;
 467            const ip4_prefix = "::ffff:";
 468            if (std.ascii.startsWithIgnoreCase(text, ip4_prefix)) {
 469                const parsed = Ip4Address.parse(text[ip4_prefix.len..], 0) catch
 470                    return .{ .invalid_ip4_mapping = ip4_prefix.len };
 471                const b = parsed.bytes;
 472                return .{ .success = .{
 473                    .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, b[0], b[1], b[2], b[3] },
 474                    .interface_name = null,
 475                } };
 476            }
 477            // Has to be u16 elements to handle 3-digit hex numbers from compression.
 478            var parts: [8]u16 = @splat(0);
 479            var parts_i: u8 = 0;
 480            var text_i: u8 = 0;
 481            var digit_i: u8 = 0;
 482            var compress_start: ?u8 = null;
 483            var interface_name_text: ?[]const u8 = null;
 484            const State = union(enum) { digit, end };
 485            state: switch (State.digit) {
 486                .digit => c: switch (text[text_i]) {
 487                    'a'...'f' => |c| {
 488                        const digit = c - 'a' + 10;
 489                        parts[parts_i] = (std.math.mul(u16, parts[parts_i], 16) catch return .{
 490                            .overflow = text_i,
 491                        }) + digit;
 492                        if (digit_i == 4) return .{ .invalid_byte = text_i };
 493                        digit_i += 1;
 494                        text_i += 1;
 495                        if (text.len - text_i == 0) {
 496                            parts_i += 1;
 497                            continue :state .end;
 498                        }
 499                        continue :c text[text_i];
 500                    },
 501                    'A'...'F' => |c| continue :c c - 'A' + 'a',
 502                    '0'...'9' => |c| {
 503                        const digit = c - '0';
 504                        parts[parts_i] = (std.math.mul(u16, parts[parts_i], 16) catch return .{
 505                            .overflow = text_i,
 506                        }) + digit;
 507                        if (digit_i == 4) return .{ .invalid_byte = text_i };
 508                        digit_i += 1;
 509                        text_i += 1;
 510                        if (text.len - text_i == 0) {
 511                            parts_i += 1;
 512                            continue :state .end;
 513                        }
 514                        continue :c text[text_i];
 515                    },
 516                    ':' => {
 517                        if (digit_i == 0) {
 518                            if (compress_start != null) return .{ .invalid_byte = text_i };
 519                            if (text_i == 0) {
 520                                text_i += 1;
 521                                if (text[text_i] != ':') return .{ .invalid_byte = text_i };
 522                                assert(parts_i == 0);
 523                            }
 524                            compress_start = parts_i;
 525                            text_i += 1;
 526                            if (text.len - text_i == 0) continue :state .end;
 527                            continue :c text[text_i];
 528                        } else {
 529                            parts_i += 1;
 530                            if (parts.len - parts_i == 0) continue :state .end;
 531                            digit_i = 0;
 532                            text_i += 1;
 533                            if (text.len - text_i == 0) return .incomplete;
 534                            continue :c text[text_i];
 535                        }
 536                    },
 537                    '%' => {
 538                        if (digit_i == 0) return .{ .invalid_byte = text_i };
 539                        parts_i += 1;
 540                        text_i += 1;
 541                        const name = text[text_i..];
 542                        if (name.len == 0) return .incomplete;
 543                        interface_name_text = name;
 544                        text_i = @intCast(text.len);
 545                        continue :state .end;
 546                    },
 547                    else => return .{ .invalid_byte = text_i },
 548                },
 549                .end => {
 550                    if (text.len - text_i != 0) return .{ .junk_after_end = text_i };
 551                    const remaining = parts.len - parts_i;
 552                    if (compress_start) |s| {
 553                        const src = parts[s..parts_i];
 554                        @memmove(parts[parts.len - src.len ..], src);
 555                        @memset(parts[s..][0..remaining], 0);
 556                    } else {
 557                        if (remaining != 0) return .incomplete;
 558                    }
 559
 560                    // Workaround that can be removed when this proposal is
 561                    // implemented https://github.com/ziglang/zig/issues/19755
 562                    if ((comptime @import("builtin").cpu.arch.endian()) != .big) {
 563                        for (&parts) |*part| part.* = @byteSwap(part.*);
 564                    }
 565
 566                    return .{ .success = .{
 567                        .bytes = @bitCast(parts),
 568                        .interface_name = interface_name_text,
 569                    } };
 570                },
 571            }
 572        }
 573
 574        pub const FromAddressError = Interface.NameError;
 575
 576        pub fn fromAddress(a: *const Ip6Address, io: Io) FromAddressError!Unresolved {
 577            if (a.interface.isNone()) return .{
 578                .bytes = a.bytes,
 579                .interface_name = null,
 580            };
 581            return .{
 582                .bytes = a.bytes,
 583                .interface_name = try a.interface.name(io),
 584            };
 585        }
 586
 587        pub fn format(u: *const Unresolved, w: *Io.Writer) Io.Writer.Error!void {
 588            const bytes = &u.bytes;
 589            if (std.mem.eql(u8, bytes[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
 590                try w.print("::ffff:{d}.{d}.{d}.{d}", .{ bytes[12], bytes[13], bytes[14], bytes[15] });
 591            } else {
 592                const parts: [8]u16 = .{
 593                    std.mem.readInt(u16, bytes[0..2], .big),
 594                    std.mem.readInt(u16, bytes[2..4], .big),
 595                    std.mem.readInt(u16, bytes[4..6], .big),
 596                    std.mem.readInt(u16, bytes[6..8], .big),
 597                    std.mem.readInt(u16, bytes[8..10], .big),
 598                    std.mem.readInt(u16, bytes[10..12], .big),
 599                    std.mem.readInt(u16, bytes[12..14], .big),
 600                    std.mem.readInt(u16, bytes[14..16], .big),
 601                };
 602
 603                // Find the longest zero run
 604                var longest_start: usize = 8;
 605                var longest_len: usize = 0;
 606                var current_start: usize = 0;
 607                var current_len: usize = 0;
 608
 609                for (parts, 0..) |part, i| {
 610                    if (part == 0) {
 611                        if (current_len == 0) {
 612                            current_start = i;
 613                        }
 614                        current_len += 1;
 615                        if (current_len > longest_len) {
 616                            longest_start = current_start;
 617                            longest_len = current_len;
 618                        }
 619                    } else {
 620                        current_len = 0;
 621                    }
 622                }
 623
 624                // Only compress if the longest zero run is 2 or more
 625                if (longest_len < 2) {
 626                    longest_start = 8;
 627                    longest_len = 0;
 628                }
 629
 630                var i: usize = 0;
 631                var abbrv = false;
 632                while (i < parts.len) : (i += 1) {
 633                    if (i == longest_start) {
 634                        // Emit "::" for the longest zero run
 635                        if (!abbrv) {
 636                            try w.writeAll(if (i == 0) "::" else ":");
 637                            abbrv = true;
 638                        }
 639                        i += longest_len - 1; // Skip the compressed range
 640                        continue;
 641                    }
 642                    if (abbrv) {
 643                        abbrv = false;
 644                    }
 645                    try w.print("{x}", .{parts[i]});
 646                    if (i != parts.len - 1) {
 647                        try w.writeAll(":");
 648                    }
 649                }
 650            }
 651            if (u.interface_name) |n| try w.print("%{s}", .{n});
 652        }
 653    };
 654
 655    pub const ParseError = error{
 656        /// If this is returned, more detailed diagnostics can be obtained by
 657        /// calling `Ip6Address.Parsed.init`.
 658        ParseFailed,
 659        /// If this is returned, the IPv6 address had a scope id on it ("%foo"
 660        /// at the end) which requires calling `resolve`.
 661        UnresolvedScope,
 662    };
 663
 664    /// This is a pure function but it cannot handle IPv6 addresses that have
 665    /// scope ids ("%foo" at the end). To also handle those, `resolve` must be
 666    /// called instead, or the lower level `Unresolved` API may be used.
 667    pub fn parse(buffer: []const u8, port: u16) ParseError!Ip6Address {
 668        switch (Unresolved.parse(buffer)) {
 669            .success => |p| return .{
 670                .bytes = p.bytes,
 671                .port = port,
 672                .interface = if (p.interface_name != null) return error.UnresolvedScope else .none,
 673            },
 674            else => return error.ParseFailed,
 675        }
 676        return .{ .ip6 = try Ip6Address.parse(buffer, port) };
 677    }
 678
 679    pub const ResolveError = error{
 680        /// If this is returned, more detailed diagnostics can be obtained by
 681        /// calling the `Parsed.init` function.
 682        ParseFailed,
 683        /// The interface name is longer than the host operating system supports.
 684        NameTooLong,
 685    } || Interface.Name.ResolveError;
 686
 687    /// This function requires an `Io` parameter because it must query the operating
 688    /// system to convert interface name to index. For example, in
 689    /// "fe80::e0e:76ff:fed4:cf22%eno1", "eno1" must be resolved to an index by
 690    /// creating a socket and then using an `ioctl` syscall.
 691    pub fn resolve(io: Io, buffer: []const u8, port: u16) ResolveError!Ip6Address {
 692        return switch (Unresolved.parse(buffer)) {
 693            .success => |p| return .{
 694                .bytes = p.bytes,
 695                .port = port,
 696                .interface = i: {
 697                    const text = p.interface_name orelse break :i .none;
 698                    const name: Interface.Name = try .fromSlice(text);
 699                    break :i try name.resolve(io);
 700                },
 701            },
 702            else => return error.ParseFailed,
 703        };
 704    }
 705
 706    pub const FormatError = Io.Writer.Error || Unresolved.FromAddressError;
 707
 708    /// Includes the optional scope ("%foo" at the end).
 709    ///
 710    /// See `format` for an alternative that omits scopes and does
 711    /// not require an `Io` parameter.
 712    pub fn formatResolved(a: Ip6Address, io: Io, w: *Io.Writer) FormatError!void {
 713        const u: Unresolved = try .fromAddress(io);
 714        try w.print("[{f}]:{d}", .{ u, a.port });
 715    }
 716
 717    /// See `formatResolved` for an alternative that additionally prints the optional
 718    /// scope at the end of addresses and requires an `Io` parameter.
 719    pub fn format(a: Ip6Address, w: *Io.Writer) Io.Writer.Error!void {
 720        const u: Unresolved = .{
 721            .bytes = a.bytes,
 722            .interface_name = null,
 723        };
 724        try w.print("[{f}]:{d}", .{ u, a.port });
 725    }
 726
 727    pub fn eql(a: Ip6Address, b: Ip6Address) bool {
 728        return a.port == b.port and std.mem.eql(u8, &a.bytes, &b.bytes);
 729    }
 730
 731    pub fn isMultiCast(a: Ip6Address) bool {
 732        return a.bytes[0] == 0xff;
 733    }
 734
 735    pub fn isLinkLocal(a: Ip6Address) bool {
 736        const b = &a.bytes;
 737        return b[0] == 0xfe and (b[1] & 0xc0) == 0x80;
 738    }
 739
 740    pub fn isLoopBack(a: Ip6Address) bool {
 741        const b = &a.bytes;
 742        return b[0] == 0 and b[1] == 0 and
 743            b[2] == 0 and
 744            b[12] == 0 and b[13] == 0 and
 745            b[14] == 0 and b[15] == 1;
 746    }
 747
 748    pub fn isSiteLocal(a: Ip6Address) bool {
 749        const b = &a.bytes;
 750        return b[0] == 0xfe and (b[1] & 0xc0) == 0xc0;
 751    }
 752
 753    pub fn policy(a: Ip6Address) *const Policy {
 754        const b = &a.bytes;
 755        for (&defined_policies) |*p| {
 756            if (!std.mem.eql(u8, b[0..p.len], p.addr[0..p.len])) continue;
 757            if ((b[p.len] & p.mask) != p.addr[p.len]) continue;
 758            return p;
 759        }
 760        unreachable;
 761    }
 762
 763    pub fn scope(a: Ip6Address) u8 {
 764        if (isMultiCast(a)) return a.bytes[1] & 15;
 765        if (isLinkLocal(a)) return 2;
 766        if (isLoopBack(a)) return 2;
 767        if (isSiteLocal(a)) return 5;
 768        return 14;
 769    }
 770
 771    const defined_policies = [_]Policy{
 772        .{
 773            .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".*,
 774            .len = 15,
 775            .mask = 0xff,
 776            .prec = 50,
 777            .label = 0,
 778        },
 779        .{
 780            .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00".*,
 781            .len = 11,
 782            .mask = 0xff,
 783            .prec = 35,
 784            .label = 4,
 785        },
 786        .{
 787            .addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
 788            .len = 1,
 789            .mask = 0xff,
 790            .prec = 30,
 791            .label = 2,
 792        },
 793        .{
 794            .addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
 795            .len = 3,
 796            .mask = 0xff,
 797            .prec = 5,
 798            .label = 5,
 799        },
 800        .{
 801            .addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
 802            .len = 0,
 803            .mask = 0xfe,
 804            .prec = 3,
 805            .label = 13,
 806        },
 807        //  These are deprecated and/or returned to the address
 808        //  pool, so despite the RFC, treating them as special
 809        //  is probably wrong.
 810        // { "", 11, 0xff, 1, 3 },
 811        // { "\xfe\xc0", 1, 0xc0, 1, 11 },
 812        // { "\x3f\xfe", 1, 0xff, 1, 12 },
 813        // Last rule must match all addresses to stop loop.
 814        .{
 815            .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
 816            .len = 0,
 817            .mask = 0,
 818            .prec = 40,
 819            .label = 1,
 820        },
 821    };
 822};
 823
 824pub const UnixAddress = struct {
 825    path: []const u8,
 826
 827    pub const max_len = 108;
 828
 829    pub const InitError = error{NameTooLong};
 830
 831    pub fn init(p: []const u8) InitError!UnixAddress {
 832        if (p.len > max_len) return error.NameTooLong;
 833        return .{ .path = p };
 834    }
 835
 836    pub const ListenError = error{
 837        AddressFamilyUnsupported,
 838        AddressInUse,
 839        NetworkDown,
 840        SystemResources,
 841        SymLinkLoop,
 842        FileNotFound,
 843        NotDir,
 844        ReadOnlyFileSystem,
 845        ProcessFdQuotaExceeded,
 846        SystemFdQuotaExceeded,
 847        AccessDenied,
 848        PermissionDenied,
 849        AddressUnavailable,
 850    } || Io.Cancelable || Io.UnexpectedError;
 851
 852    pub const ListenOptions = struct {
 853        /// How many connections the kernel will accept on the application's behalf.
 854        /// If more than this many connections pool in the kernel, clients will start
 855        /// seeing "Connection refused".
 856        kernel_backlog: u31 = default_kernel_backlog,
 857    };
 858
 859    pub fn listen(ua: *const UnixAddress, io: Io, options: ListenOptions) ListenError!Server {
 860        assert(ua.path.len <= max_len);
 861        return .{ .socket = .{
 862            .handle = try io.vtable.netListenUnix(io.userdata, ua, options),
 863            .address = .{ .ip4 = .loopback(0) },
 864        } };
 865    }
 866
 867    pub const ConnectError = error{
 868        SystemResources,
 869        ProcessFdQuotaExceeded,
 870        SystemFdQuotaExceeded,
 871        AddressFamilyUnsupported,
 872        ProtocolUnsupportedBySystem,
 873        ProtocolUnsupportedByAddressFamily,
 874        SocketModeUnsupported,
 875        AccessDenied,
 876        PermissionDenied,
 877        SymLinkLoop,
 878        FileNotFound,
 879        NotDir,
 880        ReadOnlyFileSystem,
 881        WouldBlock,
 882        NetworkDown,
 883    } || Io.Cancelable || Io.UnexpectedError;
 884
 885    pub fn connect(ua: *const UnixAddress, io: Io) ConnectError!Stream {
 886        assert(ua.path.len <= max_len);
 887        return .{ .socket = .{
 888            .handle = try io.vtable.netConnectUnix(io.userdata, ua),
 889            .address = .{ .ip4 = .loopback(0) },
 890        } };
 891    }
 892};
 893
 894pub const ReceiveFlags = packed struct(u8) {
 895    oob: bool = false,
 896    peek: bool = false,
 897    trunc: bool = false,
 898    _: u5 = 0,
 899};
 900
 901pub const IncomingMessage = struct {
 902    /// Populated by receive functions.
 903    from: IpAddress,
 904    /// Populated by receive functions, points into the caller-supplied buffer.
 905    data: []u8,
 906    /// Supplied by caller before calling receive functions; mutated by receive
 907    /// functions.
 908    control: []u8,
 909    /// Populated by receive functions.
 910    flags: Flags,
 911
 912    /// Useful for initializing before calling `receiveManyTimeout`.
 913    pub const init: IncomingMessage = .{
 914        .from = undefined,
 915        .data = undefined,
 916        .control = &.{},
 917        .flags = undefined,
 918    };
 919
 920    pub const Flags = packed struct(u8) {
 921        /// indicates end-of-record; the data returned completed a record
 922        /// (generally used with sockets of type SOCK_SEQPACKET).
 923        eor: bool,
 924        /// indicates that the trailing portion of a datagram was discarded
 925        /// because the datagram was larger than the buffer supplied.
 926        trunc: bool,
 927        /// indicates that some control data was discarded due to lack of
 928        /// space in the buffer for ancil‐ lary data.
 929        ctrunc: bool,
 930        /// indicates expedited or out-of-band data was received.
 931        oob: bool,
 932        /// indicates that no data was received but an extended error from the
 933        /// socket error queue.
 934        errqueue: bool,
 935        _: u3 = 0,
 936    };
 937};
 938
 939pub const OutgoingMessage = struct {
 940    address: *const IpAddress,
 941    data_ptr: [*]const u8,
 942    /// Initialized with how many bytes of `data_ptr` to send. After sending
 943    /// succeeds, replaced with how many bytes were actually sent.
 944    data_len: usize,
 945    control: []const u8 = &.{},
 946};
 947
 948pub const SendFlags = packed struct(u8) {
 949    confirm: bool = false,
 950    dont_route: bool = false,
 951    eor: bool = false,
 952    oob: bool = false,
 953    fastopen: bool = false,
 954    _: u3 = 0,
 955};
 956
 957pub const Interface = struct {
 958    /// Value 0 indicates `none`.
 959    index: u32,
 960
 961    pub const none: Interface = .{ .index = 0 };
 962
 963    pub const Name = struct {
 964        bytes: [max_len:0]u8,
 965
 966        pub const max_len = if (@TypeOf(std.posix.IFNAMESIZE) == void) 0 else std.posix.IFNAMESIZE - 1;
 967
 968        pub fn toSlice(n: *const Name) []const u8 {
 969            return std.mem.sliceTo(&n.bytes, 0);
 970        }
 971
 972        pub fn fromSlice(bytes: []const u8) error{NameTooLong}!Name {
 973            if (bytes.len > max_len) return error.NameTooLong;
 974            return .fromSliceUnchecked(bytes);
 975        }
 976
 977        /// Asserts bytes.len fits in `max_len`.
 978        pub fn fromSliceUnchecked(bytes: []const u8) Name {
 979            assert(bytes.len <= max_len);
 980            var result: Name = undefined;
 981            @memcpy(result.bytes[0..bytes.len], bytes);
 982            result.bytes[bytes.len] = 0;
 983            return result;
 984        }
 985
 986        pub const ResolveError = error{
 987            InterfaceNotFound,
 988            AccessDenied,
 989            SystemResources,
 990        } || Io.UnexpectedError || Io.Cancelable;
 991
 992        /// Corresponds to "if_nametoindex" in libc.
 993        pub fn resolve(n: *const Name, io: Io) ResolveError!Interface {
 994            return io.vtable.netInterfaceNameResolve(io.userdata, n);
 995        }
 996    };
 997
 998    pub const NameError = Io.UnexpectedError || Io.Cancelable;
 999
1000    /// Asserts not `none`.
1001    ///
1002    /// Corresponds to "if_indextoname" in libc.
1003    pub fn name(i: Interface, io: Io) NameError!Name {
1004        assert(i.index != 0);
1005        return io.vtable.netInterfaceName(io.userdata, i);
1006    }
1007
1008    pub fn isNone(i: Interface) bool {
1009        return i.index == 0;
1010    }
1011};
1012
1013/// An open port with unspecified protocol.
1014pub const Socket = struct {
1015    handle: Handle,
1016    /// Contains the resolved ephemeral port number if requested.
1017    address: IpAddress,
1018
1019    pub const Mode = enum {
1020        /// Provides sequenced, reliable, two-way, connection-based byte
1021        /// streams. An out-of-band data transmission mechanism may be
1022        /// supported.
1023        stream,
1024        /// Supports datagrams (connectionless, unreliable messages of a fixed
1025        /// maximum length).
1026        dgram,
1027        /// Provides  a  sequenced,  reliable,  two-way connection-based data
1028        /// transmission path for datagrams of fixed maximum length; a consumer
1029        /// is required to read an entire packet with each input system call.
1030        seqpacket,
1031        /// Provides raw network protocol access.
1032        raw,
1033        /// Provides a reliable datagram layer that does not guarantee ordering.
1034        rdm,
1035    };
1036
1037    /// Underlying platform-defined type which may or may not be
1038    /// interchangeable with a file system file descriptor.
1039    pub const Handle = switch (native_os) {
1040        .windows => std.os.windows.ws2_32.SOCKET,
1041        else => std.posix.fd_t,
1042    };
1043
1044    /// Leaves `address` in a valid state.
1045    pub fn close(s: *const Socket, io: Io) void {
1046        io.vtable.netClose(io.userdata, s.handle);
1047    }
1048
1049    pub const SendError = error{
1050        /// The socket type requires that message be sent atomically, and the
1051        /// size of the message to be sent made this impossible. The message
1052        /// was not transmitted, or was partially transmitted.
1053        MessageOversize,
1054        /// The output queue for a network interface was full. This generally indicates that the
1055        /// interface has stopped sending, but may be caused by transient congestion. (Normally,
1056        /// this does not occur in Linux. Packets are just silently dropped when a device queue
1057        /// overflows.)
1058        ///
1059        /// This is also caused when there is not enough kernel memory available.
1060        SystemResources,
1061        /// No route to network.
1062        NetworkUnreachable,
1063        /// Network reached but no route to host.
1064        HostUnreachable,
1065        /// The local network interface used to reach the destination is offline.
1066        NetworkDown,
1067        /// The destination address is not listening. Can still occur for
1068        /// connectionless messages.
1069        ConnectionRefused,
1070        /// Operating system or protocol does not support the address family.
1071        AddressFamilyUnsupported,
1072        /// Another TCP Fast Open is already in progress.
1073        FastOpenAlreadyInProgress,
1074        /// Network session was unexpectedly closed by recipient.
1075        ConnectionResetByPeer,
1076        /// Local end has been shut down on a connection-oriented socket, or
1077        /// the socket was never connected.
1078        SocketUnconnected,
1079        /// An attempt was made to send to a network/broadcast address as
1080        /// though it was a unicast address.
1081        AccessDenied,
1082    } || Io.UnexpectedError || Io.Cancelable;
1083
1084    /// Transfers `data` to `dest`, connectionless, in one packet.
1085    pub fn send(s: *const Socket, io: Io, dest: *const IpAddress, data: []const u8) SendError!void {
1086        var message: OutgoingMessage = .{ .address = dest, .data_ptr = data.ptr, .data_len = data.len };
1087        const err, const n = io.vtable.netSend(io.userdata, s.handle, (&message)[0..1], .{});
1088        if (n != 1) return err.?;
1089        if (message.data_len != data.len) return error.MessageOversize;
1090    }
1091
1092    pub fn sendMany(s: *const Socket, io: Io, messages: []OutgoingMessage, flags: SendFlags) SendError!void {
1093        return io.vtable.netSend(io.userdata, s.handle, messages, flags);
1094    }
1095
1096    pub const ReceiveError = error{
1097        /// Insufficient memory or other resource internal to the operating system.
1098        SystemResources,
1099        /// Per-process limit on the number of open file descriptors has been reached.
1100        ProcessFdQuotaExceeded,
1101        /// System-wide limit on the total number of open files has been reached.
1102        SystemFdQuotaExceeded,
1103        /// Local end has been shut down on a connection-oriented socket, or
1104        /// the socket was never connected.
1105        SocketUnconnected,
1106        /// The socket type requires that message be sent atomically, and the
1107        /// size of the message to be sent made this impossible. The message
1108        /// was not transmitted, or was partially transmitted.
1109        MessageOversize,
1110        /// Network connection was unexpectedly closed by sender.
1111        ConnectionResetByPeer,
1112        /// The local network interface used to reach the destination is offline.
1113        NetworkDown,
1114    } || Io.UnexpectedError || Io.Cancelable;
1115
1116    /// Waits for data. Connectionless.
1117    ///
1118    /// See also:
1119    /// * `receiveTimeout`
1120    pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {
1121        var message: IncomingMessage = .init;
1122        const maybe_err, const count = io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, .none);
1123        if (maybe_err) |err| switch (err) {
1124            // No timeout is passed to `netReceieve`, so it must not return timeout related errors.
1125            error.Timeout, error.UnsupportedClock => unreachable,
1126            else => |e| return e,
1127        };
1128        assert(1 == count);
1129        return message;
1130    }
1131
1132    pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error;
1133
1134    /// Waits for data. Connectionless.
1135    ///
1136    /// Returns `error.Timeout` if no message arrives early enough.
1137    ///
1138    /// See also:
1139    /// * `receive`
1140    /// * `receiveManyTimeout`
1141    pub fn receiveTimeout(
1142        s: *const Socket,
1143        io: Io,
1144        buffer: []u8,
1145        timeout: Io.Timeout,
1146    ) ReceiveTimeoutError!IncomingMessage {
1147        var message: IncomingMessage = .init;
1148        const maybe_err, const count = io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, timeout);
1149        if (maybe_err) |err| return err;
1150        assert(1 == count);
1151        return message;
1152    }
1153
1154    /// Waits until at least one message is delivered, possibly returning more
1155    /// than one message. Connectionless.
1156    ///
1157    /// Returns number of messages received, or `error.Timeout` if no message
1158    /// arrives early enough.
1159    ///
1160    /// See also:
1161    /// * `receive`
1162    /// * `receiveTimeout`
1163    pub fn receiveManyTimeout(
1164        s: *const Socket,
1165        io: Io,
1166        /// Function assumes each element has initialized `control` field.
1167        /// Initializing with `IncomingMessage.init` may be helpful.
1168        message_buffer: []IncomingMessage,
1169        data_buffer: []u8,
1170        flags: ReceiveFlags,
1171        timeout: Io.Timeout,
1172    ) struct { ?ReceiveTimeoutError, usize } {
1173        return io.vtable.netReceive(io.userdata, s.handle, message_buffer, data_buffer, flags, timeout);
1174    }
1175};
1176
1177/// An open socket connection with a network protocol that guarantees
1178/// sequencing, delivery, and prevents repetition. Typically TCP or UNIX domain
1179/// socket.
1180pub const Stream = struct {
1181    socket: Socket,
1182
1183    const max_iovecs_len = 8;
1184
1185    pub fn close(s: *const Stream, io: Io) void {
1186        io.vtable.netClose(io.userdata, s.socket.handle);
1187    }
1188
1189    pub const Reader = struct {
1190        io: Io,
1191        interface: Io.Reader,
1192        stream: Stream,
1193        err: ?Error,
1194
1195        pub const Error = error{
1196            SystemResources,
1197            ConnectionResetByPeer,
1198            Timeout,
1199            SocketUnconnected,
1200            /// The file descriptor does not hold the required rights to read
1201            /// from it.
1202            AccessDenied,
1203            NetworkDown,
1204        } || Io.Cancelable || Io.UnexpectedError;
1205
1206        pub fn init(stream: Stream, io: Io, buffer: []u8) Reader {
1207            return .{
1208                .io = io,
1209                .interface = .{
1210                    .vtable = &.{
1211                        .stream = streamImpl,
1212                        .readVec = readVec,
1213                    },
1214                    .buffer = buffer,
1215                    .seek = 0,
1216                    .end = 0,
1217                },
1218                .stream = stream,
1219                .err = null,
1220            };
1221        }
1222
1223        fn streamImpl(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
1224            const dest = limit.slice(try io_w.writableSliceGreedy(1));
1225            var data: [1][]u8 = .{dest};
1226            const n = try readVec(io_r, &data);
1227            io_w.advance(n);
1228            return n;
1229        }
1230
1231        fn readVec(io_r: *Io.Reader, data: [][]u8) Io.Reader.Error!usize {
1232            const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r));
1233            const io = r.io;
1234            var iovecs_buffer: [max_iovecs_len][]u8 = undefined;
1235            const dest_n, const data_size = try io_r.writableVector(&iovecs_buffer, data);
1236            const dest = iovecs_buffer[0..dest_n];
1237            assert(dest[0].len > 0);
1238            const n = io.vtable.netRead(io.userdata, r.stream.socket.handle, dest) catch |err| {
1239                r.err = err;
1240                return error.ReadFailed;
1241            };
1242            if (n == 0) {
1243                return error.EndOfStream;
1244            }
1245            if (n > data_size) {
1246                r.interface.end += n - data_size;
1247                return data_size;
1248            }
1249            return n;
1250        }
1251    };
1252
1253    pub const Writer = struct {
1254        io: Io,
1255        interface: Io.Writer,
1256        stream: Stream,
1257        err: ?Error = null,
1258
1259        pub const Error = error{
1260            /// Another TCP Fast Open is already in progress.
1261            FastOpenAlreadyInProgress,
1262            /// Network session was unexpectedly closed by recipient.
1263            ConnectionResetByPeer,
1264            /// The output queue for a network interface was full. This generally indicates that the
1265            /// interface has stopped sending, but may be caused by transient congestion. (Normally,
1266            /// this does not occur in Linux. Packets are just silently dropped when a device queue
1267            /// overflows.)
1268            ///
1269            /// This is also caused when there is not enough kernel memory available.
1270            SystemResources,
1271            /// No route to network.
1272            NetworkUnreachable,
1273            /// Network reached but no route to host.
1274            HostUnreachable,
1275            /// The local network interface used to reach the destination is down.
1276            NetworkDown,
1277            /// The destination address is not listening.
1278            ConnectionRefused,
1279            /// The passed address didn't have the correct address family in its sa_family field.
1280            AddressFamilyUnsupported,
1281            /// Local end has been shut down on a connection-oriented socket, or
1282            /// the socket was never connected.
1283            SocketUnconnected,
1284            SocketNotBound,
1285        } || Io.UnexpectedError || Io.Cancelable;
1286
1287        pub fn init(stream: Stream, io: Io, buffer: []u8) Writer {
1288            return .{
1289                .io = io,
1290                .stream = stream,
1291                .interface = .{
1292                    .vtable = &.{ .drain = drain },
1293                    .buffer = buffer,
1294                },
1295            };
1296        }
1297
1298        fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
1299            const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
1300            const io = w.io;
1301            const buffered = io_w.buffered();
1302            const handle = w.stream.socket.handle;
1303            const n = io.vtable.netWrite(io.userdata, handle, buffered, data, splat) catch |err| {
1304                w.err = err;
1305                return error.WriteFailed;
1306            };
1307            return io_w.consume(n);
1308        }
1309    };
1310
1311    pub fn reader(stream: Stream, io: Io, buffer: []u8) Reader {
1312        return .init(stream, io, buffer);
1313    }
1314
1315    pub fn writer(stream: Stream, io: Io, buffer: []u8) Writer {
1316        return .init(stream, io, buffer);
1317    }
1318};
1319
1320pub const Server = struct {
1321    socket: Socket,
1322
1323    pub fn deinit(s: *Server, io: Io) void {
1324        s.socket.close(io);
1325        s.* = undefined;
1326    }
1327
1328    pub const AcceptError = error{
1329        /// The per-process limit on the number of open file descriptors has been reached.
1330        ProcessFdQuotaExceeded,
1331        /// The system-wide limit on the total number of open files has been reached.
1332        SystemFdQuotaExceeded,
1333        /// Not enough free memory. This often means that the memory allocation is limited
1334        /// by the socket buffer limits, not by the system memory.
1335        SystemResources,
1336        /// Either `listen` was never called, or `shutdown` was called (possibly while
1337        /// this call was blocking). This allows `shutdown` to be used as a concurrent
1338        /// cancellation mechanism.
1339        SocketNotListening,
1340        /// The network subsystem has failed.
1341        NetworkDown,
1342        /// No connection is already queued and ready to be accepted, and
1343        /// the socket is configured as non-blocking.
1344        WouldBlock,
1345        /// An incoming connection was indicated, but was subsequently terminated by the
1346        /// remote peer prior to accepting the call.
1347        ConnectionAborted,
1348        /// Firewall rules forbid connection.
1349        BlockedByFirewall,
1350        ProtocolFailure,
1351    } || Io.UnexpectedError || Io.Cancelable;
1352
1353    /// Blocks until a client connects to the server.
1354    pub fn accept(s: *Server, io: Io) AcceptError!Stream {
1355        return io.vtable.netAccept(io.userdata, s.socket.handle);
1356    }
1357};
1358
1359test "parsing IPv6 addresses" {
1360    try testIp6Parse("fe80::e0e:76ff:fed4:cf22%eno1");
1361    try testIp6Parse("2001:db8::1");
1362    try testIp6ParseTransform("2001:db8::1", "2001:0db8:0000:0000:0000:0000:0000:0001");
1363    try testIp6Parse("::1");
1364    try testIp6Parse("::");
1365    try testIp6Parse("fe80::1");
1366    try testIp6Parse("fe80::abcd:ef12%3");
1367    try testIp6Parse("ff02::");
1368    try testIp6Parse("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
1369}
1370
1371fn testIp6Parse(input: []const u8) !void {
1372    return testIp6ParseTransform(input, input);
1373}
1374
1375fn testIp6ParseTransform(expected: []const u8, input: []const u8) !void {
1376    const ua = switch (Ip6Address.Unresolved.parse(input)) {
1377        .success => |p| p,
1378        else => |x| {
1379            std.debug.print("failed to parse \"{s}\": {any}\n", .{ input, x });
1380            return error.TestFailed;
1381        },
1382    };
1383    var buffer: [100]u8 = undefined;
1384    const result = try std.fmt.bufPrint(&buffer, "{f}", .{ua});
1385    try std.testing.expectEqualStrings(expected, result);
1386}
1387
1388test {
1389    _ = HostName;
1390    _ = @import("net/test.zig");
1391}