authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-13 22:05:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
log0732ff22638a0e4b53bd2c42565165679674b3e1
tree3a33d53b091a711be52f53951d31f1d0e5a5d88d
parente8cea8accb7f289fd00ee82063df32882748ac48

std.Io.Threaded: implement connecting to unix sockets


3 files changed, 110 insertions(+), 90 deletions(-)

BRANCH_TODO+2-1
...@@ -5,11 +5,12 @@...@@ -5,11 +5,12 @@
5* fix Group.wait not handling cancelation (need to move impl of ResetEvent to Threaded)5* fix Group.wait not handling cancelation (need to move impl of ResetEvent to Threaded)
6* implement cancelRequest for non-linux posix6* implement cancelRequest for non-linux posix
7* finish converting all Threaded into directly calling system functions and handling EINTR7* finish converting all Threaded into directly calling system functions and handling EINTR
8* audit the TODOs
89
9* move max_iovecs_len to std.Io10* move max_iovecs_len to std.Io
10* address the cancelation race condition (signal received between checkCancel and syscall)11* address the cancelation race condition (signal received between checkCancel and syscall)
11* update signal values to be an enum12* update signal values to be an enum
12* move fs.File.Writer to Io13* move fs.File.Writer to Io
13* add non-blocking flag to network operations, handle EAGAIN14* add non-blocking flag to net and fs operations, handle EAGAIN
14* finish moving std.fs to Io15* finish moving std.fs to Io
15* finish moving all of std.posix into Threaded16* finish moving all of std.posix into Threaded
lib/std/Io/Threaded.zig+79-87
...@@ -1697,34 +1697,10 @@ fn netListenIpPosix(...@@ -1697,34 +1697,10 @@ fn netListenIpPosix(
1697) Io.net.IpAddress.ListenError!Io.net.Server {1697) Io.net.IpAddress.ListenError!Io.net.Server {
1698 const pool: *Pool = @ptrCast(@alignCast(userdata));1698 const pool: *Pool = @ptrCast(@alignCast(userdata));
1699 const family = posixAddressFamily(&address);1699 const family = posixAddressFamily(&address);
1700 const protocol: u32 = posix.IPPROTO.TCP;1700 const socket_fd = try openSocketPosix(pool, family, .{
1701 const socket_fd = while (true) {1701 .mode = options.mode,
1702 try pool.checkCancel();1702 .protocol = options.protocol,
1703 const flags: u32 = posix.SOCK.STREAM | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;1703 });
1704 const socket_rc = posix.system.socket(family, flags, protocol);
1705 switch (posix.errno(socket_rc)) {
1706 .SUCCESS => {
1707 const fd: posix.fd_t = @intCast(socket_rc);
1708 errdefer posix.close(fd);
1709 if (socket_flags_unsupported) while (true) {
1710 try pool.checkCancel();
1711 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
1712 .SUCCESS => break,
1713 .INTR => continue,
1714 else => |err| return posix.unexpectedErrno(err),
1715 }
1716 };
1717 break fd;
1718 },
1719 .INTR => continue,
1720 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
1721 .MFILE => return error.ProcessFdQuotaExceeded,
1722 .NFILE => return error.SystemFdQuotaExceeded,
1723 .NOBUFS => return error.SystemResources,
1724 .NOMEM => return error.SystemResources,
1725 else => |err| return posix.unexpectedErrno(err),
1726 }
1727 };
1728 errdefer posix.close(socket_fd);1704 errdefer posix.close(socket_fd);
17291705
1730 if (options.reuse_address) {1706 if (options.reuse_address) {
...@@ -1763,53 +1739,49 @@ fn netListenUnix(...@@ -1763,53 +1739,49 @@ fn netListenUnix(
1763) Io.net.UnixAddress.ListenError!Io.net.Socket.Handle {1739) Io.net.UnixAddress.ListenError!Io.net.Socket.Handle {
1764 if (!Io.net.has_unix_sockets) return error.AddressFamilyUnsupported;1740 if (!Io.net.has_unix_sockets) return error.AddressFamilyUnsupported;
1765 const pool: *Pool = @ptrCast(@alignCast(userdata));1741 const pool: *Pool = @ptrCast(@alignCast(userdata));
1766 const protocol: u32 = 0;1742 const socket_fd = openSocketPosix(pool, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
1767 const socket_fd = while (true) {1743 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
1768 try pool.checkCancel();1744 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
1769 const flags: u32 = posix.SOCK.STREAM | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;1745 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
1770 const socket_rc = posix.system.socket(posix.AF.UNIX, flags, protocol);1746 else => |e| return e,
1771 switch (posix.errno(socket_rc)) {
1772 .SUCCESS => {
1773 const fd: posix.fd_t = @intCast(socket_rc);
1774 errdefer posix.close(fd);
1775 if (socket_flags_unsupported) while (true) {
1776 try pool.checkCancel();
1777 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
1778 .SUCCESS => break,
1779 .INTR => continue,
1780 else => |err| return posix.unexpectedErrno(err),
1781 }
1782 };
1783 break fd;
1784 },
1785 .INTR => continue,
1786 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
1787 .MFILE => return error.ProcessFdQuotaExceeded,
1788 .NFILE => return error.SystemFdQuotaExceeded,
1789 .NOBUFS => return error.SystemResources,
1790 .NOMEM => return error.SystemResources,
1791 else => |err| return posix.unexpectedErrno(err),
1792 }
1793 };1747 };
1794 errdefer posix.close(socket_fd);1748 errdefer posix.close(socket_fd);
17951749
1796 var storage: UnixAddress = undefined;1750 var storage: UnixAddress = undefined;
1797 const addr_len = addressUnixToPosix(address, &storage);1751 const addr_len = addressUnixToPosix(address, &storage);
1752 try posixBindUnix(pool, socket_fd, &storage.any, addr_len);
1753
1798 while (true) {1754 while (true) {
1799 try pool.checkCancel();1755 try pool.checkCancel();
1800 switch (posix.errno(posix.system.bind(socket_fd, &storage.any, addr_len))) {1756 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
1757 .SUCCESS => break,
1758 .ADDRINUSE => return error.AddressInUse,
1759 .BADF => |err| return errnoBug(err),
1760 else => |err| return posix.unexpectedErrno(err),
1761 }
1762 }
1763
1764 return socket_fd;
1765}
1766
1767fn posixBindUnix(pool: *Pool, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
1768 while (true) {
1769 try pool.checkCancel();
1770 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {
1801 .SUCCESS => break,1771 .SUCCESS => break,
1802 .INTR => continue,1772 .INTR => continue,
1803 .ACCES => return error.AccessDenied,1773 .ACCES => return error.AccessDenied,
1804 .PERM => return error.PermissionDenied,
1805 .ADDRINUSE => return error.AddressInUse,1774 .ADDRINUSE => return error.AddressInUse,
1806 .AFNOSUPPORT => return error.AddressFamilyUnsupported,1775 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
1807 .ADDRNOTAVAIL => return error.AddressUnavailable,1776 .ADDRNOTAVAIL => return error.AddressUnavailable,
1808 .NOMEM => return error.SystemResources,1777 .NOMEM => return error.SystemResources,
1778
1809 .LOOP => return error.SymLinkLoop,1779 .LOOP => return error.SymLinkLoop,
1810 .NOENT => return error.FileNotFound,1780 .NOENT => return error.FileNotFound,
1811 .NOTDIR => return error.NotDir,1781 .NOTDIR => return error.NotDir,
1812 .ROFS => return error.ReadOnlyFileSystem,1782 .ROFS => return error.ReadOnlyFileSystem,
1783 .PERM => return error.PermissionDenied,
1784
1813 .BADF => |err| return errnoBug(err), // always a race condition if this error is returned1785 .BADF => |err| return errnoBug(err), // always a race condition if this error is returned
1814 .INVAL => |err| return errnoBug(err), // invalid parameters1786 .INVAL => |err| return errnoBug(err), // invalid parameters
1815 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`1787 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
...@@ -1818,18 +1790,6 @@ fn netListenUnix(...@@ -1818,18 +1790,6 @@ fn netListenUnix(
1818 else => |err| return posix.unexpectedErrno(err),1790 else => |err| return posix.unexpectedErrno(err),
1819 }1791 }
1820 }1792 }
1821
1822 while (true) {
1823 try pool.checkCancel();
1824 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
1825 .SUCCESS => break,
1826 .ADDRINUSE => return error.AddressInUse,
1827 .BADF => |err| return errnoBug(err),
1828 else => |err| return posix.unexpectedErrno(err),
1829 }
1830 }
1831
1832 return socket_fd;
1833}1793}
18341794
1835fn posixBind(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {1795fn posixBind(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
...@@ -1857,7 +1817,6 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka...@@ -1857,7 +1817,6 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka
1857 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {1817 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
1858 .SUCCESS => return,1818 .SUCCESS => return,
1859 .INTR => continue,1819 .INTR => continue,
1860 .ADDRINUSE => return error.AddressInUse,
1861 .ADDRNOTAVAIL => return error.AddressUnavailable,1820 .ADDRNOTAVAIL => return error.AddressUnavailable,
1862 .AFNOSUPPORT => return error.AddressFamilyUnsupported,1821 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
1863 .AGAIN, .INPROGRESS => return error.WouldBlock,1822 .AGAIN, .INPROGRESS => return error.WouldBlock,
...@@ -1866,7 +1825,7 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka...@@ -1866,7 +1825,7 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka
1866 .CONNREFUSED => return error.ConnectionRefused,1825 .CONNREFUSED => return error.ConnectionRefused,
1867 .CONNRESET => return error.ConnectionResetByPeer,1826 .CONNRESET => return error.ConnectionResetByPeer,
1868 .FAULT => |err| return errnoBug(err),1827 .FAULT => |err| return errnoBug(err),
1869 .ISCONN => return error.AlreadyConnected,1828 .ISCONN => |err| return errnoBug(err),
1870 .HOSTUNREACH => return error.HostUnreachable,1829 .HOSTUNREACH => return error.HostUnreachable,
1871 .NETUNREACH => return error.NetworkUnreachable,1830 .NETUNREACH => return error.NetworkUnreachable,
1872 .NOTSOCK => |err| return errnoBug(err),1831 .NOTSOCK => |err| return errnoBug(err),
...@@ -1874,7 +1833,6 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka...@@ -1874,7 +1833,6 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka
1874 .TIMEDOUT => return error.ConnectionTimedOut,1833 .TIMEDOUT => return error.ConnectionTimedOut,
1875 .CONNABORTED => |err| return errnoBug(err),1834 .CONNABORTED => |err| return errnoBug(err),
1876 .ACCES => return error.AccessDenied,1835 .ACCES => return error.AccessDenied,
1877 // UNIX socket error codes:
1878 .PERM => |err| return errnoBug(err),1836 .PERM => |err| return errnoBug(err),
1879 .NOENT => |err| return errnoBug(err),1837 .NOENT => |err| return errnoBug(err),
1880 else => |err| return posix.unexpectedErrno(err),1838 else => |err| return posix.unexpectedErrno(err),
...@@ -1882,6 +1840,35 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka...@@ -1882,6 +1840,35 @@ fn posixConnect(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.socka
1882 }1840 }
1883}1841}
18841842
1843fn posixConnectUnix(pool: *Pool, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
1844 while (true) {
1845 try pool.checkCancel();
1846 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {
1847 .SUCCESS => return,
1848 .INTR => continue,
1849
1850 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
1851 .AGAIN => return error.WouldBlock,
1852 .INPROGRESS => return error.WouldBlock,
1853 .ACCES => return error.AccessDenied,
1854
1855 .LOOP => return error.SymLinkLoop,
1856 .NOENT => return error.FileNotFound,
1857 .NOTDIR => return error.NotDir,
1858 .ROFS => return error.ReadOnlyFileSystem,
1859 .PERM => return error.PermissionDenied,
1860
1861 .BADF => |err| return errnoBug(err),
1862 .CONNABORTED => |err| return errnoBug(err),
1863 .FAULT => |err| return errnoBug(err),
1864 .ISCONN => |err| return errnoBug(err),
1865 .NOTSOCK => |err| return errnoBug(err),
1866 .PROTOTYPE => |err| return errnoBug(err),
1867 else => |err| return posix.unexpectedErrno(err),
1868 }
1869 }
1870}
1871
1885fn posixGetSockName(pool: *Pool, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {1872fn posixGetSockName(pool: *Pool, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {
1886 while (true) {1873 while (true) {
1887 try pool.checkCancel();1874 try pool.checkCancel();
...@@ -1926,6 +1913,7 @@ fn netConnectIpPosix(...@@ -1926,6 +1913,7 @@ fn netConnectIpPosix(
1926 .mode = options.mode,1913 .mode = options.mode,
1927 .protocol = options.protocol,1914 .protocol = options.protocol,
1928 });1915 });
1916 errdefer posix.close(socket_fd);
1929 var storage: PosixAddress = undefined;1917 var storage: PosixAddress = undefined;
1930 var addr_len = addressToPosix(address, &storage);1918 var addr_len = addressToPosix(address, &storage);
1931 try posixConnect(pool, socket_fd, &storage.any, addr_len);1919 try posixConnect(pool, socket_fd, &storage.any, addr_len);
...@@ -1940,10 +1928,14 @@ fn netConnectUnix(...@@ -1940,10 +1928,14 @@ fn netConnectUnix(
1940 userdata: ?*anyopaque,1928 userdata: ?*anyopaque,
1941 address: *const Io.net.UnixAddress,1929 address: *const Io.net.UnixAddress,
1942) Io.net.UnixAddress.ConnectError!Io.net.Socket.Handle {1930) Io.net.UnixAddress.ConnectError!Io.net.Socket.Handle {
1931 if (!Io.net.has_unix_sockets) return error.AddressFamilyUnsupported;
1943 const pool: *Pool = @ptrCast(@alignCast(userdata));1932 const pool: *Pool = @ptrCast(@alignCast(userdata));
1944 _ = pool;1933 const socket_fd = try openSocketPosix(pool, posix.AF.UNIX, .{ .mode = .stream });
1945 _ = address;1934 errdefer posix.close(socket_fd);
1946 @panic("TODO");1935 var storage: UnixAddress = undefined;
1936 const addr_len = addressUnixToPosix(address, &storage);
1937 try posixConnectUnix(pool, socket_fd, &storage.any, addr_len);
1938 return socket_fd;
1947}1939}
19481940
1949fn netBindIpPosix(1941fn netBindIpPosix(
...@@ -2497,18 +2489,16 @@ fn netInterfaceNameResolve(...@@ -2497,18 +2489,16 @@ fn netInterfaceNameResolve(
2497 name: *const Io.net.Interface.Name,2489 name: *const Io.net.Interface.Name,
2498) Io.net.Interface.Name.ResolveError!Io.net.Interface {2490) Io.net.Interface.Name.ResolveError!Io.net.Interface {
2499 const pool: *Pool = @ptrCast(@alignCast(userdata));2491 const pool: *Pool = @ptrCast(@alignCast(userdata));
2500 try pool.checkCancel();
25012492
2502 if (native_os == .linux) {2493 if (native_os == .linux) {
2503 const rc = posix.system.socket(posix.AF.UNIX, posix.SOCK.DGRAM | posix.SOCK.CLOEXEC, 0);2494 const sock_fd = openSocketPosix(pool, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
2504 const sock_fd: posix.fd_t = switch (posix.errno(rc)) {2495 error.ProcessFdQuotaExceeded => return error.SystemResources,
2505 .SUCCESS => @intCast(rc),2496 error.SystemFdQuotaExceeded => return error.SystemResources,
2506 .ACCES => return error.AccessDenied,2497 error.AddressFamilyUnsupported => return error.Unexpected,
2507 .MFILE => return error.SystemResources,2498 error.ProtocolUnsupportedBySystem => return error.Unexpected,
2508 .NFILE => return error.SystemResources,2499 error.ProtocolUnsupportedByAddressFamily => return error.Unexpected,
2509 .NOBUFS => return error.SystemResources,2500 error.SocketModeUnsupported => return error.Unexpected,
2510 .NOMEM => return error.SystemResources,2501 else => |e| return e,
2511 else => |err| return posix.unexpectedErrno(err),
2512 };2502 };
2513 defer posix.close(sock_fd);2503 defer posix.close(sock_fd);
25142504
...@@ -2521,12 +2511,12 @@ fn netInterfaceNameResolve(...@@ -2521,12 +2511,12 @@ fn netInterfaceNameResolve(
2521 try pool.checkCancel();2511 try pool.checkCancel();
2522 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {2512 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
2523 .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },2513 .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },
2514 .INTR => continue,
2524 .INVAL => |err| return errnoBug(err), // Bad parameters.2515 .INVAL => |err| return errnoBug(err), // Bad parameters.
2525 .NOTTY => |err| return errnoBug(err),2516 .NOTTY => |err| return errnoBug(err),
2526 .NXIO => |err| return errnoBug(err),2517 .NXIO => |err| return errnoBug(err),
2527 .BADF => |err| return errnoBug(err), // Always a race condition.2518 .BADF => |err| return errnoBug(err), // Always a race condition.
2528 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.2519 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
2529 .INTR => continue,
2530 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor2520 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
2531 .NODEV => return error.InterfaceNotFound,2521 .NODEV => return error.InterfaceNotFound,
2532 else => |err| return posix.unexpectedErrno(err),2522 else => |err| return posix.unexpectedErrno(err),
...@@ -2535,12 +2525,14 @@ fn netInterfaceNameResolve(...@@ -2535,12 +2525,14 @@ fn netInterfaceNameResolve(
2535 }2525 }
25362526
2537 if (native_os == .windows) {2527 if (native_os == .windows) {
2528 try pool.checkCancel();
2538 const index = std.os.windows.ws2_32.if_nametoindex(&name.bytes);2529 const index = std.os.windows.ws2_32.if_nametoindex(&name.bytes);
2539 if (index == 0) return error.InterfaceNotFound;2530 if (index == 0) return error.InterfaceNotFound;
2540 return .{ .index = index };2531 return .{ .index = index };
2541 }2532 }
25422533
2543 if (builtin.link_libc) {2534 if (builtin.link_libc) {
2535 try pool.checkCancel();
2544 const index = std.c.if_nametoindex(&name.bytes);2536 const index = std.c.if_nametoindex(&name.bytes);
2545 if (index == 0) return error.InterfaceNotFound;2537 if (index == 0) return error.InterfaceNotFound;
2546 return .{ .index = @bitCast(index) };2538 return .{ .index = @bitCast(index) };
...@@ -2591,7 +2583,7 @@ fn addressFromPosix(posix_address: *PosixAddress) Io.net.IpAddress {...@@ -2591,7 +2583,7 @@ fn addressFromPosix(posix_address: *PosixAddress) Io.net.IpAddress {
2591 return switch (posix_address.any.family) {2583 return switch (posix_address.any.family) {
2592 posix.AF.INET => .{ .ip4 = address4FromPosix(&posix_address.in) },2584 posix.AF.INET => .{ .ip4 = address4FromPosix(&posix_address.in) },
2593 posix.AF.INET6 => .{ .ip6 = address6FromPosix(&posix_address.in6) },2585 posix.AF.INET6 => .{ .ip6 = address6FromPosix(&posix_address.in6) },
2594 else => unreachable,2586 else => .{ .ip4 = .loopback(0) },
2595 };2587 };
2596}2588}
25972589
lib/std/Io/net.zig+29-2
...@@ -206,6 +206,9 @@ pub const IpAddress = union(enum) {...@@ -206,6 +206,9 @@ pub const IpAddress = union(enum) {
206 SystemFdQuotaExceeded,206 SystemFdQuotaExceeded,
207 /// The requested address family (IPv4 or IPv6) is not supported by the operating system.207 /// The requested address family (IPv4 or IPv6) is not supported by the operating system.
208 AddressFamilyUnsupported,208 AddressFamilyUnsupported,
209 ProtocolUnsupportedBySystem,
210 ProtocolUnsupportedByAddressFamily,
211 SocketModeUnsupported,
209 } || Io.UnexpectedError || Io.Cancelable;212 } || Io.UnexpectedError || Io.Cancelable;
210213
211 pub const ListenOptions = struct {214 pub const ListenOptions = struct {
...@@ -216,6 +219,16 @@ pub const IpAddress = union(enum) {...@@ -216,6 +219,16 @@ pub const IpAddress = union(enum) {
216 /// Sets SO_REUSEADDR and SO_REUSEPORT on POSIX.219 /// Sets SO_REUSEADDR and SO_REUSEPORT on POSIX.
217 /// Sets SO_REUSEADDR on Windows, which is roughly equivalent.220 /// Sets SO_REUSEADDR on Windows, which is roughly equivalent.
218 reuse_address: bool = false,221 reuse_address: bool = false,
222 /// Only connection-oriented modes may be used here, which includes:
223 /// * `Socket.Mode.stream`
224 /// * `Socket.Mode.seqpacket`
225 mode: Socket.Mode = .stream,
226 /// Only connection-oriented protocols may be used here, which includes:
227 /// * `Protocol.tcp`
228 /// * `Protocol.tp`
229 /// * `Protocol.dccp`
230 /// * `Protocol.sctp`
231 protocol: Protocol = .tcp,
219 };232 };
220233
221 /// Waits for a TCP connection. When using this API, `bind` does not need234 /// Waits for a TCP connection. When using this API, `bind` does not need
...@@ -276,7 +289,6 @@ pub const IpAddress = union(enum) {...@@ -276,7 +289,6 @@ pub const IpAddress = union(enum) {
276 ConnectionPending,289 ConnectionPending,
277 ConnectionRefused,290 ConnectionRefused,
278 ConnectionResetByPeer,291 ConnectionResetByPeer,
279 AlreadyConnected,
280 HostUnreachable,292 HostUnreachable,
281 NetworkUnreachable,293 NetworkUnreachable,
282 ConnectionTimedOut,294 ConnectionTimedOut,
...@@ -842,7 +854,22 @@ pub const UnixAddress = struct {...@@ -842,7 +854,22 @@ pub const UnixAddress = struct {
842 } };854 } };
843 }855 }
844856
845 pub const ConnectError = error{} || Io.Cancelable || Io.UnexpectedError;857 pub const ConnectError = error{
858 SystemResources,
859 ProcessFdQuotaExceeded,
860 SystemFdQuotaExceeded,
861 AddressFamilyUnsupported,
862 ProtocolUnsupportedBySystem,
863 ProtocolUnsupportedByAddressFamily,
864 SocketModeUnsupported,
865 AccessDenied,
866 PermissionDenied,
867 SymLinkLoop,
868 FileNotFound,
869 NotDir,
870 ReadOnlyFileSystem,
871 WouldBlock,
872 } || Io.Cancelable || Io.UnexpectedError;
846873
847 pub fn connect(ua: *const UnixAddress, io: Io) ConnectError!Stream {874 pub fn connect(ua: *const UnixAddress, io: Io) ConnectError!Stream {
848 assert(ua.path.len <= max_len);875 assert(ua.path.len <= max_len);