| ... | @@ -250,6 +250,19 @@ pub fn io(t: *Threaded) Io { | ... | @@ -250,6 +250,19 @@ pub fn io(t: *Threaded) Io { |
| 250 | }; | 250 | }; |
| 251 | } | 251 | } |
| 252 | | 252 | |
| | 253 | const socket_flags_unsupported = builtin.os.tag.isDarwin() or native_os == .haiku; // 💩💩 |
| | 254 | const have_accept4 = !socket_flags_unsupported; |
| | 255 | const have_flock_open_flags = @hasField(posix.O, "EXLOCK"); |
| | 256 | const have_networking = builtin.os.tag != .wasi; |
| | 257 | const have_flock = @TypeOf(posix.system.flock) != void; |
| | 258 | const have_sendmmsg = builtin.os.tag == .linux; |
| | 259 | |
| | 260 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| | 261 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; |
| | 262 | const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat; |
| | 263 | const lseek_sym = if (posix.lfs64_abi) posix.system.lseek64 else posix.system.lseek; |
| | 264 | const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system.preadv; |
| | 265 | |
| 253 | /// Trailing data: | 266 | /// Trailing data: |
| 254 | /// 1. context | 267 | /// 1. context |
| 255 | /// 2. result | 268 | /// 2. result |
| ... | @@ -1143,13 +1156,6 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. | ... | @@ -1143,13 +1156,6 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. |
| 1143 | } | 1156 | } |
| 1144 | } | 1157 | } |
| 1145 | | 1158 | |
| 1146 | const have_flock = @TypeOf(posix.system.flock) != void; | | |
| 1147 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | | |
| 1148 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; | | |
| 1149 | const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat; | | |
| 1150 | const lseek_sym = if (posix.lfs64_abi) posix.system.lseek64 else posix.system.lseek; | | |
| 1151 | const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system.preadv; | | |
| 1152 | | | |
| 1153 | fn dirAccessPosix( | 1159 | fn dirAccessPosix( |
| 1154 | userdata: ?*anyopaque, | 1160 | userdata: ?*anyopaque, |
| 1155 | dir: Io.Dir, | 1161 | dir: Io.Dir, |
| ... | @@ -1277,8 +1283,7 @@ fn dirCreateFilePosix( | ... | @@ -1277,8 +1283,7 @@ fn dirCreateFilePosix( |
| 1277 | // Use the O locking flags if the os supports them to acquire the lock | 1283 | // Use the O locking flags if the os supports them to acquire the lock |
| 1278 | // atomically. Note that the NONBLOCK flag is removed after the openat() | 1284 | // atomically. Note that the NONBLOCK flag is removed after the openat() |
| 1279 | // call is successful. | 1285 | // call is successful. |
| 1280 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | 1286 | if (have_flock_open_flags) switch (flags.lock) { |
| 1281 | if (has_flock_open_flags) switch (flags.lock) { | | |
| 1282 | .none => {}, | 1287 | .none => {}, |
| 1283 | .shared => { | 1288 | .shared => { |
| 1284 | os_flags.SHLOCK = true; | 1289 | os_flags.SHLOCK = true; |
| ... | @@ -1328,7 +1333,7 @@ fn dirCreateFilePosix( | ... | @@ -1328,7 +1333,7 @@ fn dirCreateFilePosix( |
| 1328 | }; | 1333 | }; |
| 1329 | errdefer posix.close(fd); | 1334 | errdefer posix.close(fd); |
| 1330 | | 1335 | |
| 1331 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | 1336 | if (have_flock and !have_flock_open_flags and flags.lock != .none) { |
| 1332 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | 1337 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; |
| 1333 | const lock_flags = switch (flags.lock) { | 1338 | const lock_flags = switch (flags.lock) { |
| 1334 | .none => unreachable, | 1339 | .none => unreachable, |
| ... | @@ -1352,7 +1357,7 @@ fn dirCreateFilePosix( | ... | @@ -1352,7 +1357,7 @@ fn dirCreateFilePosix( |
| 1352 | } | 1357 | } |
| 1353 | } | 1358 | } |
| 1354 | | 1359 | |
| 1355 | if (has_flock_open_flags and flags.lock_nonblocking) { | 1360 | if (have_flock_open_flags and flags.lock_nonblocking) { |
| 1356 | var fl_flags: usize = while (true) { | 1361 | var fl_flags: usize = while (true) { |
| 1357 | try t.checkCancel(); | 1362 | try t.checkCancel(); |
| 1358 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); | 1363 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); |
| ... | @@ -1476,8 +1481,7 @@ fn dirOpenFile( | ... | @@ -1476,8 +1481,7 @@ fn dirOpenFile( |
| 1476 | | 1481 | |
| 1477 | // Use the O locking flags if the os supports them to acquire the lock | 1482 | // Use the O locking flags if the os supports them to acquire the lock |
| 1478 | // atomically. | 1483 | // atomically. |
| 1479 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | 1484 | if (have_flock_open_flags) { |
| 1480 | if (has_flock_open_flags) { | | |
| 1481 | // Note that the NONBLOCK flag is removed after the openat() call | 1485 | // Note that the NONBLOCK flag is removed after the openat() call |
| 1482 | // is successful. | 1486 | // is successful. |
| 1483 | switch (flags.lock) { | 1487 | switch (flags.lock) { |
| ... | @@ -1530,7 +1534,7 @@ fn dirOpenFile( | ... | @@ -1530,7 +1534,7 @@ fn dirOpenFile( |
| 1530 | }; | 1534 | }; |
| 1531 | errdefer posix.close(fd); | 1535 | errdefer posix.close(fd); |
| 1532 | | 1536 | |
| 1533 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | 1537 | if (have_flock and !have_flock_open_flags and flags.lock != .none) { |
| 1534 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | 1538 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; |
| 1535 | const lock_flags = switch (flags.lock) { | 1539 | const lock_flags = switch (flags.lock) { |
| 1536 | .none => unreachable, | 1540 | .none => unreachable, |
| ... | @@ -1554,7 +1558,7 @@ fn dirOpenFile( | ... | @@ -1554,7 +1558,7 @@ fn dirOpenFile( |
| 1554 | } | 1558 | } |
| 1555 | } | 1559 | } |
| 1556 | | 1560 | |
| 1557 | if (has_flock_open_flags and flags.lock_nonblocking) { | 1561 | if (have_flock_open_flags and flags.lock_nonblocking) { |
| 1558 | var fl_flags: usize = while (true) { | 1562 | var fl_flags: usize = while (true) { |
| 1559 | try t.checkCancel(); | 1563 | try t.checkCancel(); |
| 1560 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); | 1564 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); |
| ... | @@ -1954,7 +1958,7 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { | ... | @@ -1954,7 +1958,7 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 1954 | var ns: std.os.wasi.timestamp_t = undefined; | 1958 | var ns: std.os.wasi.timestamp_t = undefined; |
| 1955 | const err = std.os.wasi.clock_time_get(clockToWasi(clock), 1, &ns); | 1959 | const err = std.os.wasi.clock_time_get(clockToWasi(clock), 1, &ns); |
| 1956 | if (err != .SUCCESS) return error.Unexpected; | 1960 | if (err != .SUCCESS) return error.Unexpected; |
| 1957 | return ns; | 1961 | return .fromNanoseconds(ns); |
| 1958 | } | 1962 | } |
| 1959 | | 1963 | |
| 1960 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | 1964 | fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| ... | @@ -2004,7 +2008,7 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -2004,7 +2008,7 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2004 | | 2008 | |
| 2005 | const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t.io())) |d| .{ | 2009 | const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t.io())) |d| .{ |
| 2006 | .id = clockToWasi(d.clock), | 2010 | .id = clockToWasi(d.clock), |
| 2007 | .timeout = std.math.lossyCast(u64, d.duration.nanoseconds), | 2011 | .timeout = std.math.lossyCast(u64, d.raw.nanoseconds), |
| 2008 | .precision = 0, | 2012 | .precision = 0, |
| 2009 | .flags = 0, | 2013 | .flags = 0, |
| 2010 | } else .{ | 2014 | } else .{ |
| ... | @@ -2083,6 +2087,7 @@ fn netListenIpPosix( | ... | @@ -2083,6 +2087,7 @@ fn netListenIpPosix( |
| 2083 | address: IpAddress, | 2087 | address: IpAddress, |
| 2084 | options: IpAddress.ListenOptions, | 2088 | options: IpAddress.ListenOptions, |
| 2085 | ) IpAddress.ListenError!net.Server { | 2089 | ) IpAddress.ListenError!net.Server { |
| | 2090 | if (!have_networking) return error.NetworkDown; |
| 2086 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2091 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2087 | const family = posixAddressFamily(&address); | 2092 | const family = posixAddressFamily(&address); |
| 2088 | const socket_fd = try openSocketPosix(t, family, .{ | 2093 | const socket_fd = try openSocketPosix(t, family, .{ |
| ... | @@ -2230,6 +2235,7 @@ fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sock | ... | @@ -2230,6 +2235,7 @@ fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sock |
| 2230 | .ACCES => return error.AccessDenied, | 2235 | .ACCES => return error.AccessDenied, |
| 2231 | .PERM => |err| return errnoBug(err), | 2236 | .PERM => |err| return errnoBug(err), |
| 2232 | .NOENT => |err| return errnoBug(err), | 2237 | .NOENT => |err| return errnoBug(err), |
| | 2238 | .NETDOWN => return error.NetworkDown, |
| 2233 | else => |err| return posix.unexpectedErrno(err), | 2239 | else => |err| return posix.unexpectedErrno(err), |
| 2234 | } | 2240 | } |
| 2235 | } | 2241 | } |
| ... | @@ -2306,6 +2312,7 @@ fn netConnectIpPosix( | ... | @@ -2306,6 +2312,7 @@ fn netConnectIpPosix( |
| 2306 | address: *const IpAddress, | 2312 | address: *const IpAddress, |
| 2307 | options: IpAddress.ConnectOptions, | 2313 | options: IpAddress.ConnectOptions, |
| 2308 | ) IpAddress.ConnectError!net.Stream { | 2314 | ) IpAddress.ConnectError!net.Stream { |
| | 2315 | if (!have_networking) return error.NetworkDown; |
| 2309 | if (options.timeout != .none) @panic("TODO"); | 2316 | if (options.timeout != .none) @panic("TODO"); |
| 2310 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2317 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2311 | const family = posixAddressFamily(address); | 2318 | const family = posixAddressFamily(address); |
| ... | @@ -2346,6 +2353,7 @@ fn netBindIpPosix( | ... | @@ -2346,6 +2353,7 @@ fn netBindIpPosix( |
| 2346 | address: *const IpAddress, | 2353 | address: *const IpAddress, |
| 2347 | options: IpAddress.BindOptions, | 2354 | options: IpAddress.BindOptions, |
| 2348 | ) IpAddress.BindError!net.Socket { | 2355 | ) IpAddress.BindError!net.Socket { |
| | 2356 | if (!have_networking) return error.NetworkDown; |
| 2349 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2357 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2350 | const family = posixAddressFamily(address); | 2358 | const family = posixAddressFamily(address); |
| 2351 | const socket_fd = try openSocketPosix(t, family, options); | 2359 | const socket_fd = try openSocketPosix(t, family, options); |
| ... | @@ -2421,9 +2429,6 @@ fn openSocketPosix( | ... | @@ -2421,9 +2429,6 @@ fn openSocketPosix( |
| 2421 | return socket_fd; | 2429 | return socket_fd; |
| 2422 | } | 2430 | } |
| 2423 | | 2431 | |
| 2424 | const socket_flags_unsupported = builtin.os.tag.isDarwin() or native_os == .haiku; // 💩💩 | | |
| 2425 | const have_accept4 = !socket_flags_unsupported; | | |
| 2426 | | | |
| 2427 | fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream { | 2432 | fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream { |
| 2428 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2433 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2429 | var storage: PosixAddress = undefined; | 2434 | var storage: PosixAddress = undefined; |
| ... | @@ -2534,14 +2539,13 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net. | ... | @@ -2534,14 +2539,13 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net. |
| 2534 | } | 2539 | } |
| 2535 | } | 2540 | } |
| 2536 | | 2541 | |
| 2537 | const have_sendmmsg = builtin.os.tag == .linux; | | |
| 2538 | | | |
| 2539 | fn netSend( | 2542 | fn netSend( |
| 2540 | userdata: ?*anyopaque, | 2543 | userdata: ?*anyopaque, |
| 2541 | handle: net.Socket.Handle, | 2544 | handle: net.Socket.Handle, |
| 2542 | messages: []net.OutgoingMessage, | 2545 | messages: []net.OutgoingMessage, |
| 2543 | flags: net.SendFlags, | 2546 | flags: net.SendFlags, |
| 2544 | ) struct { ?net.Socket.SendError, usize } { | 2547 | ) struct { ?net.Socket.SendError, usize } { |
| | 2548 | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 2545 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2549 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2546 | | 2550 | |
| 2547 | const posix_flags: u32 = | 2551 | const posix_flags: u32 = |
| ... | @@ -2703,7 +2707,7 @@ fn netSendMany( | ... | @@ -2703,7 +2707,7 @@ fn netSendMany( |
| 2703 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. | 2707 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. |
| 2704 | .PIPE => return error.SocketUnconnected, | 2708 | .PIPE => return error.SocketUnconnected, |
| 2705 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, | 2709 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 2706 | .HOSTUNREACH => return error.NetworkUnreachable, | 2710 | .HOSTUNREACH => return error.HostUnreachable, |
| 2707 | .NETUNREACH => return error.NetworkUnreachable, | 2711 | .NETUNREACH => return error.NetworkUnreachable, |
| 2708 | .NOTCONN => return error.SocketUnconnected, | 2712 | .NOTCONN => return error.SocketUnconnected, |
| 2709 | .NETDOWN => return error.NetworkDown, | 2713 | .NETDOWN => return error.NetworkDown, |
| ... | @@ -2720,6 +2724,7 @@ fn netReceive( | ... | @@ -2720,6 +2724,7 @@ fn netReceive( |
| 2720 | flags: net.ReceiveFlags, | 2724 | flags: net.ReceiveFlags, |
| 2721 | timeout: Io.Timeout, | 2725 | timeout: Io.Timeout, |
| 2722 | ) struct { ?net.Socket.ReceiveTimeoutError, usize } { | 2726 | ) struct { ?net.Socket.ReceiveTimeoutError, usize } { |
| | 2727 | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 2723 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2728 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2724 | | 2729 | |
| 2725 | // recvmmsg is useless, here's why: | 2730 | // recvmmsg is useless, here's why: |
| ... | @@ -2847,8 +2852,8 @@ fn netWritePosix( | ... | @@ -2847,8 +2852,8 @@ fn netWritePosix( |
| 2847 | data: []const []const u8, | 2852 | data: []const []const u8, |
| 2848 | splat: usize, | 2853 | splat: usize, |
| 2849 | ) net.Stream.Writer.Error!usize { | 2854 | ) net.Stream.Writer.Error!usize { |
| | 2855 | if (!have_networking) return error.NetworkDown; |
| 2850 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2856 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2851 | try t.checkCancel(); | | |
| 2852 | | 2857 | |
| 2853 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; | 2858 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| 2854 | var msg: posix.msghdr_const = .{ | 2859 | var msg: posix.msghdr_const = .{ |
| ... | @@ -2889,7 +2894,37 @@ fn netWritePosix( | ... | @@ -2889,7 +2894,37 @@ fn netWritePosix( |
| 2889 | }, | 2894 | }, |
| 2890 | }; | 2895 | }; |
| 2891 | const flags = posix.MSG.NOSIGNAL; | 2896 | const flags = posix.MSG.NOSIGNAL; |
| 2892 | return posix.sendmsg(fd, &msg, flags); | 2897 | while (true) { |
| | 2898 | try t.checkCancel(); |
| | 2899 | const rc = posix.system.sendmsg(fd, &msg, flags); |
| | 2900 | switch (posix.errno(rc)) { |
| | 2901 | .SUCCESS => return @intCast(rc), |
| | 2902 | .INTR => continue, |
| | 2903 | .CANCELED => return error.Canceled, |
| | 2904 | |
| | 2905 | .ACCES => |err| return errnoBug(err), |
| | 2906 | .AGAIN => |err| return errnoBug(err), |
| | 2907 | .ALREADY => return error.FastOpenAlreadyInProgress, |
| | 2908 | .BADF => |err| return errnoBug(err), // always a race condition |
| | 2909 | .CONNRESET => return error.ConnectionResetByPeer, |
| | 2910 | .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set. |
| | 2911 | .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument. |
| | 2912 | .INVAL => |err| return errnoBug(err), // Invalid argument passed. |
| | 2913 | .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified |
| | 2914 | .MSGSIZE => |err| return errnoBug(err), |
| | 2915 | .NOBUFS => return error.SystemResources, |
| | 2916 | .NOMEM => return error.SystemResources, |
| | 2917 | .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket. |
| | 2918 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. |
| | 2919 | .PIPE => return error.SocketUnconnected, |
| | 2920 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| | 2921 | .HOSTUNREACH => return error.HostUnreachable, |
| | 2922 | .NETUNREACH => return error.NetworkUnreachable, |
| | 2923 | .NOTCONN => return error.SocketUnconnected, |
| | 2924 | .NETDOWN => return error.NetworkDown, |
| | 2925 | else => |err| return posix.unexpectedErrno(err), |
| | 2926 | } |
| | 2927 | } |
| 2893 | } | 2928 | } |
| 2894 | | 2929 | |
| 2895 | fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { | 2930 | fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { |
| ... | @@ -2913,6 +2948,7 @@ fn netInterfaceNameResolve( | ... | @@ -2913,6 +2948,7 @@ fn netInterfaceNameResolve( |
| 2913 | userdata: ?*anyopaque, | 2948 | userdata: ?*anyopaque, |
| 2914 | name: *const net.Interface.Name, | 2949 | name: *const net.Interface.Name, |
| 2915 | ) net.Interface.Name.ResolveError!net.Interface { | 2950 | ) net.Interface.Name.ResolveError!net.Interface { |
| | 2951 | if (!have_networking) return error.InterfaceNotFound; |
| 2916 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2952 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2917 | | 2953 | |
| 2918 | if (native_os == .linux) { | 2954 | if (native_os == .linux) { |