| ... | ... | @@ -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 | 266 | /// Trailing data: |
| 254 | 267 | /// 1. context |
| 255 | 268 | /// 2. result |
| ... | ... | @@ -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 | 1159 | fn dirAccessPosix( |
| 1154 | 1160 | userdata: ?*anyopaque, |
| 1155 | 1161 | dir: Io.Dir, |
| ... | ... | @@ -1277,8 +1283,7 @@ fn dirCreateFilePosix( |
| 1277 | 1283 | // Use the O locking flags if the os supports them to acquire the lock |
| 1278 | 1284 | // atomically. Note that the NONBLOCK flag is removed after the openat() |
| 1279 | 1285 | // call is successful. |
| 1280 | | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); |
| 1281 | | if (has_flock_open_flags) switch (flags.lock) { |
| 1286 | if (have_flock_open_flags) switch (flags.lock) { |
| 1282 | 1287 | .none => {}, |
| 1283 | 1288 | .shared => { |
| 1284 | 1289 | os_flags.SHLOCK = true; |
| ... | ... | @@ -1328,7 +1333,7 @@ fn dirCreateFilePosix( |
| 1328 | 1333 | }; |
| 1329 | 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 | 1337 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; |
| 1333 | 1338 | const lock_flags = switch (flags.lock) { |
| 1334 | 1339 | .none => unreachable, |
| ... | ... | @@ -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 | 1361 | var fl_flags: usize = while (true) { |
| 1357 | 1362 | try t.checkCancel(); |
| 1358 | 1363 | const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0)); |
| ... | ... | @@ -1476,8 +1481,7 @@ fn dirOpenFile( |
| 1476 | 1481 | |
| 1477 | 1482 | // Use the O locking flags if the os supports them to acquire the lock |
| 1478 | 1483 | // atomically. |
| 1479 | | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); |
| 1480 | | if (has_flock_open_flags) { |
| 1484 | if (have_flock_open_flags) { |
| 1481 | 1485 | // Note that the NONBLOCK flag is removed after the openat() call |
| 1482 | 1486 | // is successful. |
| 1483 | 1487 | switch (flags.lock) { |
| ... | ... | @@ -1530,7 +1534,7 @@ fn dirOpenFile( |
| 1530 | 1534 | }; |
| 1531 | 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 | 1538 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; |
| 1535 | 1539 | const lock_flags = switch (flags.lock) { |
| 1536 | 1540 | .none => unreachable, |
| ... | ... | @@ -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 | 1562 | var fl_flags: usize = while (true) { |
| 1559 | 1563 | try t.checkCancel(); |
| 1560 | 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 | 1958 | var ns: std.os.wasi.timestamp_t = undefined; |
| 1955 | 1959 | const err = std.os.wasi.clock_time_get(clockToWasi(clock), 1, &ns); |
| 1956 | 1960 | if (err != .SUCCESS) return error.Unexpected; |
| 1957 | | return ns; |
| 1961 | return .fromNanoseconds(ns); |
| 1958 | 1962 | } |
| 1959 | 1963 | |
| 1960 | 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 | 2008 | |
| 2005 | 2009 | const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t.io())) |d| .{ |
| 2006 | 2010 | .id = clockToWasi(d.clock), |
| 2007 | | .timeout = std.math.lossyCast(u64, d.duration.nanoseconds), |
| 2011 | .timeout = std.math.lossyCast(u64, d.raw.nanoseconds), |
| 2008 | 2012 | .precision = 0, |
| 2009 | 2013 | .flags = 0, |
| 2010 | 2014 | } else .{ |
| ... | ... | @@ -2083,6 +2087,7 @@ fn netListenIpPosix( |
| 2083 | 2087 | address: IpAddress, |
| 2084 | 2088 | options: IpAddress.ListenOptions, |
| 2085 | 2089 | ) IpAddress.ListenError!net.Server { |
| 2090 | if (!have_networking) return error.NetworkDown; |
| 2086 | 2091 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2087 | 2092 | const family = posixAddressFamily(&address); |
| 2088 | 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 | 2235 | .ACCES => return error.AccessDenied, |
| 2231 | 2236 | .PERM => |err| return errnoBug(err), |
| 2232 | 2237 | .NOENT => |err| return errnoBug(err), |
| 2238 | .NETDOWN => return error.NetworkDown, |
| 2233 | 2239 | else => |err| return posix.unexpectedErrno(err), |
| 2234 | 2240 | } |
| 2235 | 2241 | } |
| ... | ... | @@ -2306,6 +2312,7 @@ fn netConnectIpPosix( |
| 2306 | 2312 | address: *const IpAddress, |
| 2307 | 2313 | options: IpAddress.ConnectOptions, |
| 2308 | 2314 | ) IpAddress.ConnectError!net.Stream { |
| 2315 | if (!have_networking) return error.NetworkDown; |
| 2309 | 2316 | if (options.timeout != .none) @panic("TODO"); |
| 2310 | 2317 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2311 | 2318 | const family = posixAddressFamily(address); |
| ... | ... | @@ -2346,6 +2353,7 @@ fn netBindIpPosix( |
| 2346 | 2353 | address: *const IpAddress, |
| 2347 | 2354 | options: IpAddress.BindOptions, |
| 2348 | 2355 | ) IpAddress.BindError!net.Socket { |
| 2356 | if (!have_networking) return error.NetworkDown; |
| 2349 | 2357 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2350 | 2358 | const family = posixAddressFamily(address); |
| 2351 | 2359 | const socket_fd = try openSocketPosix(t, family, options); |
| ... | ... | @@ -2421,9 +2429,6 @@ fn openSocketPosix( |
| 2421 | 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 | 2432 | fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream { |
| 2428 | 2433 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2429 | 2434 | var storage: PosixAddress = undefined; |
| ... | ... | @@ -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 | 2542 | fn netSend( |
| 2540 | 2543 | userdata: ?*anyopaque, |
| 2541 | 2544 | handle: net.Socket.Handle, |
| 2542 | 2545 | messages: []net.OutgoingMessage, |
| 2543 | 2546 | flags: net.SendFlags, |
| 2544 | 2547 | ) struct { ?net.Socket.SendError, usize } { |
| 2548 | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 2545 | 2549 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2546 | 2550 | |
| 2547 | 2551 | const posix_flags: u32 = |
| ... | ... | @@ -2703,7 +2707,7 @@ fn netSendMany( |
| 2703 | 2707 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. |
| 2704 | 2708 | .PIPE => return error.SocketUnconnected, |
| 2705 | 2709 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 2706 | | .HOSTUNREACH => return error.NetworkUnreachable, |
| 2710 | .HOSTUNREACH => return error.HostUnreachable, |
| 2707 | 2711 | .NETUNREACH => return error.NetworkUnreachable, |
| 2708 | 2712 | .NOTCONN => return error.SocketUnconnected, |
| 2709 | 2713 | .NETDOWN => return error.NetworkDown, |
| ... | ... | @@ -2720,6 +2724,7 @@ fn netReceive( |
| 2720 | 2724 | flags: net.ReceiveFlags, |
| 2721 | 2725 | timeout: Io.Timeout, |
| 2722 | 2726 | ) struct { ?net.Socket.ReceiveTimeoutError, usize } { |
| 2727 | if (!have_networking) return .{ error.NetworkDown, 0 }; |
| 2723 | 2728 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2724 | 2729 | |
| 2725 | 2730 | // recvmmsg is useless, here's why: |
| ... | ... | @@ -2847,8 +2852,8 @@ fn netWritePosix( |
| 2847 | 2852 | data: []const []const u8, |
| 2848 | 2853 | splat: usize, |
| 2849 | 2854 | ) net.Stream.Writer.Error!usize { |
| 2855 | if (!have_networking) return error.NetworkDown; |
| 2850 | 2856 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2851 | | try t.checkCancel(); |
| 2852 | 2857 | |
| 2853 | 2858 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| 2854 | 2859 | var msg: posix.msghdr_const = .{ |
| ... | ... | @@ -2889,7 +2894,37 @@ fn netWritePosix( |
| 2889 | 2894 | }, |
| 2890 | 2895 | }; |
| 2891 | 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 | 2930 | fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { |
| ... | ... | @@ -2913,6 +2948,7 @@ fn netInterfaceNameResolve( |
| 2913 | 2948 | userdata: ?*anyopaque, |
| 2914 | 2949 | name: *const net.Interface.Name, |
| 2915 | 2950 | ) net.Interface.Name.ResolveError!net.Interface { |
| 2951 | if (!have_networking) return error.InterfaceNotFound; |
| 2916 | 2952 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2917 | 2953 | |
| 2918 | 2954 | if (native_os == .linux) { |