| ... | ... | @@ -124,8 +124,19 @@ pub fn io(pool: *Pool) Io { |
| 124 | 124 | .now = now, |
| 125 | 125 | .sleep = sleep, |
| 126 | 126 | |
| 127 | | .listen = listen, |
| 128 | | .accept = accept, |
| 127 | .listen = switch (builtin.os.tag) { |
| 128 | .windows => @panic("TODO"), |
| 129 | else => listenPosix, |
| 130 | }, |
| 131 | .accept = switch (builtin.os.tag) { |
| 132 | .windows => @panic("TODO"), |
| 133 | else => acceptPosix, |
| 134 | }, |
| 135 | .ipBind = switch (builtin.os.tag) { |
| 136 | .windows => @panic("TODO"), |
| 137 | else => ipBindPosix, |
| 138 | }, |
| 139 | .netClose = netClose, |
| 129 | 140 | .netRead = switch (builtin.os.tag) { |
| 130 | 141 | .windows => @panic("TODO"), |
| 131 | 142 | else => netReadPosix, |
| ... | ... | @@ -134,7 +145,8 @@ pub fn io(pool: *Pool) Io { |
| 134 | 145 | .windows => @panic("TODO"), |
| 135 | 146 | else => netWritePosix, |
| 136 | 147 | }, |
| 137 | | .netClose = netClose, |
| 148 | .netSend = netSend, |
| 149 | .netReceive = netReceive, |
| 138 | 150 | .netInterfaceNameResolve = netInterfaceNameResolve, |
| 139 | 151 | .netInterfaceName = netInterfaceName, |
| 140 | 152 | }, |
| ... | ... | @@ -460,7 +472,7 @@ fn asyncDetached( |
| 460 | 472 | |
| 461 | 473 | fn await( |
| 462 | 474 | userdata: ?*anyopaque, |
| 463 | | any_future: *std.Io.AnyFuture, |
| 475 | any_future: *Io.AnyFuture, |
| 464 | 476 | result: []u8, |
| 465 | 477 | result_alignment: std.mem.Alignment, |
| 466 | 478 | ) void { |
| ... | ... | @@ -984,59 +996,228 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { |
| 984 | 996 | return result.?; |
| 985 | 997 | } |
| 986 | 998 | |
| 987 | | fn listen(userdata: ?*anyopaque, address: Io.net.IpAddress, options: Io.net.ListenOptions) Io.net.ListenError!Io.net.Server { |
| 999 | fn listenPosix( |
| 1000 | userdata: ?*anyopaque, |
| 1001 | address: Io.net.IpAddress, |
| 1002 | options: Io.net.IpAddress.ListenOptions, |
| 1003 | ) Io.net.IpAddress.ListenError!Io.net.Server { |
| 988 | 1004 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 989 | | try pool.checkCancel(); |
| 990 | | |
| 991 | | const nonblock: u32 = if (options.force_nonblocking) posix.SOCK.NONBLOCK else 0; |
| 992 | | const sock_flags = posix.SOCK.STREAM | posix.SOCK.CLOEXEC | nonblock; |
| 993 | | const proto: u32 = posix.IPPROTO.TCP; |
| 994 | | const family = posixAddressFamily(address); |
| 995 | | const sockfd = try posix.socket(family, sock_flags, proto); |
| 996 | | const stream: std.net.Stream = .{ .handle = sockfd }; |
| 997 | | errdefer stream.close(); |
| 1005 | const family = posixAddressFamily(&address); |
| 1006 | const protocol: u32 = posix.IPPROTO.TCP; |
| 1007 | const socket_fd = while (true) { |
| 1008 | try pool.checkCancel(); |
| 1009 | const flags: u32 = posix.SOCK.STREAM | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC; |
| 1010 | const socket_rc = posix.system.socket(family, flags, protocol); |
| 1011 | switch (posix.errno(socket_rc)) { |
| 1012 | .SUCCESS => { |
| 1013 | const fd: posix.fd_t = @intCast(socket_rc); |
| 1014 | errdefer posix.close(fd); |
| 1015 | if (socket_flags_unsupported) while (true) { |
| 1016 | try pool.checkCancel(); |
| 1017 | switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, posix.FD_CLOEXEC))) { |
| 1018 | .SUCCESS => break, |
| 1019 | .INTR => continue, |
| 1020 | else => |err| return posix.unexpectedErrno(err), |
| 1021 | } |
| 1022 | }; |
| 1023 | break fd; |
| 1024 | }, |
| 1025 | .INTR => continue, |
| 1026 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 1027 | .MFILE => return error.ProcessFdQuotaExceeded, |
| 1028 | .NFILE => return error.SystemFdQuotaExceeded, |
| 1029 | .NOBUFS => return error.SystemResources, |
| 1030 | .NOMEM => return error.SystemResources, |
| 1031 | else => |err| return posix.unexpectedErrno(err), |
| 1032 | } |
| 1033 | }; |
| 1034 | errdefer posix.close(socket_fd); |
| 998 | 1035 | |
| 999 | 1036 | if (options.reuse_address) { |
| 1000 | | try posix.setsockopt( |
| 1001 | | sockfd, |
| 1002 | | posix.SOL.SOCKET, |
| 1003 | | posix.SO.REUSEADDR, |
| 1004 | | &std.mem.toBytes(@as(c_int, 1)), |
| 1005 | | ); |
| 1006 | | if (@hasDecl(posix.SO, "REUSEPORT") and family != posix.AF.UNIX) { |
| 1007 | | try posix.setsockopt( |
| 1008 | | sockfd, |
| 1009 | | posix.SOL.SOCKET, |
| 1010 | | posix.SO.REUSEPORT, |
| 1011 | | &std.mem.toBytes(@as(c_int, 1)), |
| 1012 | | ); |
| 1013 | | } |
| 1037 | try setSocketOption(pool, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1); |
| 1038 | if (@hasDecl(posix.SO, "REUSEPORT")) |
| 1039 | try setSocketOption(pool, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1); |
| 1014 | 1040 | } |
| 1015 | 1041 | |
| 1016 | 1042 | var storage: PosixAddress = undefined; |
| 1017 | 1043 | var socklen = addressToPosix(address, &storage); |
| 1018 | | try posix.bind(sockfd, &storage.any, socklen); |
| 1019 | | try posix.listen(sockfd, options.kernel_backlog); |
| 1020 | | try posix.getsockname(sockfd, &storage.any, &socklen); |
| 1044 | try posixBind(pool, socket_fd, &storage.any, socklen); |
| 1045 | |
| 1046 | while (true) { |
| 1047 | try pool.checkCancel(); |
| 1048 | switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) { |
| 1049 | .SUCCESS => break, |
| 1050 | .ADDRINUSE => return error.AddressInUse, |
| 1051 | .BADF => |err| return errnoBug(err), |
| 1052 | else => |err| return posix.unexpectedErrno(err), |
| 1053 | } |
| 1054 | } |
| 1055 | |
| 1056 | try posixGetSockName(pool, socket_fd, &storage.any, &socklen); |
| 1021 | 1057 | return .{ |
| 1022 | | .listen_address = addressFromPosix(&storage), |
| 1023 | | .stream = .{ .handle = stream.handle }, |
| 1058 | .socket = .{ |
| 1059 | .handle = socket_fd, |
| 1060 | .address = addressFromPosix(&storage), |
| 1061 | }, |
| 1024 | 1062 | }; |
| 1025 | 1063 | } |
| 1026 | 1064 | |
| 1027 | | fn accept(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptError!Io.net.Server.Connection { |
| 1065 | fn posixBind(pool: *Pool, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void { |
| 1066 | while (true) { |
| 1067 | try pool.checkCancel(); |
| 1068 | switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) { |
| 1069 | .SUCCESS => break, |
| 1070 | .INTR => continue, |
| 1071 | .ADDRINUSE => return error.AddressInUse, |
| 1072 | .BADF => |err| return errnoBug(err), // always a race condition if this error is returned |
| 1073 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 1074 | .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd` |
| 1075 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 1076 | .ADDRNOTAVAIL => return error.AddressUnavailable, |
| 1077 | .FAULT => |err| return errnoBug(err), // invalid `addr` pointer |
| 1078 | .NOMEM => return error.SystemResources, |
| 1079 | else => |err| return posix.unexpectedErrno(err), |
| 1080 | } |
| 1081 | } |
| 1082 | } |
| 1083 | |
| 1084 | fn posixGetSockName(pool: *Pool, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void { |
| 1085 | while (true) { |
| 1086 | try pool.checkCancel(); |
| 1087 | switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) { |
| 1088 | .SUCCESS => break, |
| 1089 | .INTR => continue, |
| 1090 | .BADF => |err| return errnoBug(err), // always a race condition |
| 1091 | .FAULT => |err| return errnoBug(err), |
| 1092 | .INVAL => |err| return errnoBug(err), // invalid parameters |
| 1093 | .NOTSOCK => |err| return errnoBug(err), // always a race condition |
| 1094 | .NOBUFS => return error.SystemResources, |
| 1095 | else => |err| return posix.unexpectedErrno(err), |
| 1096 | } |
| 1097 | } |
| 1098 | } |
| 1099 | |
| 1100 | fn setSocketOption(pool: *Pool, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void { |
| 1101 | const o: []const u8 = @ptrCast(&option); |
| 1102 | while (true) { |
| 1103 | try pool.checkCancel(); |
| 1104 | switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) { |
| 1105 | .SUCCESS => return, |
| 1106 | .INTR => continue, |
| 1107 | .BADF => |err| return errnoBug(err), // always a race condition |
| 1108 | .NOTSOCK => |err| return errnoBug(err), // always a race condition |
| 1109 | .INVAL => |err| return errnoBug(err), |
| 1110 | .FAULT => |err| return errnoBug(err), |
| 1111 | else => |err| return posix.unexpectedErrno(err), |
| 1112 | } |
| 1113 | } |
| 1114 | } |
| 1115 | |
| 1116 | fn ipBindPosix( |
| 1117 | userdata: ?*anyopaque, |
| 1118 | address: Io.net.IpAddress, |
| 1119 | options: Io.net.IpAddress.BindOptions, |
| 1120 | ) Io.net.IpAddress.BindError!Io.net.Socket { |
| 1028 | 1121 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1029 | | try pool.checkCancel(); |
| 1122 | const mode = posixSocketMode(options.mode); |
| 1123 | const family = posixAddressFamily(&address); |
| 1124 | const protocol = posixProtocol(options.protocol); |
| 1125 | const socket_fd = while (true) { |
| 1126 | try pool.checkCancel(); |
| 1127 | const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC; |
| 1128 | const socket_rc = posix.system.socket(family, flags, protocol); |
| 1129 | switch (posix.errno(socket_rc)) { |
| 1130 | .SUCCESS => { |
| 1131 | const fd: posix.fd_t = @intCast(socket_rc); |
| 1132 | errdefer posix.close(fd); |
| 1133 | if (socket_flags_unsupported) while (true) { |
| 1134 | try pool.checkCancel(); |
| 1135 | switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, posix.FD_CLOEXEC))) { |
| 1136 | .SUCCESS => break, |
| 1137 | .INTR => continue, |
| 1138 | else => |err| return posix.unexpectedErrno(err), |
| 1139 | } |
| 1140 | }; |
| 1141 | break fd; |
| 1142 | }, |
| 1143 | .INTR => continue, |
| 1144 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 1145 | .INVAL => return error.ProtocolUnsupportedBySystem, |
| 1146 | .MFILE => return error.ProcessFdQuotaExceeded, |
| 1147 | .NFILE => return error.SystemFdQuotaExceeded, |
| 1148 | .NOBUFS => return error.SystemResources, |
| 1149 | .NOMEM => return error.SystemResources, |
| 1150 | .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily, |
| 1151 | .PROTOTYPE => return error.SocketModeUnsupported, |
| 1152 | else => |err| return posix.unexpectedErrno(err), |
| 1153 | } |
| 1154 | }; |
| 1155 | |
| 1156 | if (options.ip6_only) { |
| 1157 | try setSocketOption(pool, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0); |
| 1158 | } |
| 1030 | 1159 | |
| 1031 | 1160 | var storage: PosixAddress = undefined; |
| 1032 | | var addr_len: posix.socklen_t = @sizeOf(PosixAddress); |
| 1033 | | const fd = try posix.accept(server.stream.handle, &storage.any, &addr_len, posix.SOCK.CLOEXEC); |
| 1161 | var socklen = addressToPosix(address, &storage); |
| 1162 | try posixBind(pool, socket_fd, &storage.any, socklen); |
| 1163 | try posixGetSockName(pool, socket_fd, &storage.any, &socklen); |
| 1034 | 1164 | return .{ |
| 1035 | | .stream = .{ .handle = fd }, |
| 1165 | .handle = socket_fd, |
| 1036 | 1166 | .address = addressFromPosix(&storage), |
| 1037 | 1167 | }; |
| 1038 | 1168 | } |
| 1039 | 1169 | |
| 1170 | const socket_flags_unsupported = builtin.os.tag.isDarwin() or native_os == .haiku; // 💩💩 |
| 1171 | const have_accept4 = !socket_flags_unsupported; |
| 1172 | |
| 1173 | fn acceptPosix(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptError!Io.net.Stream { |
| 1174 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1175 | const listen_fd = server.socket.handle; |
| 1176 | var storage: PosixAddress = undefined; |
| 1177 | var addr_len: posix.socklen_t = @sizeOf(PosixAddress); |
| 1178 | const fd = while (true) { |
| 1179 | try pool.checkCancel(); |
| 1180 | const rc = if (have_accept4) |
| 1181 | posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC) |
| 1182 | else |
| 1183 | posix.system.accept(listen_fd, &storage.any, &addr_len); |
| 1184 | switch (posix.errno(rc)) { |
| 1185 | .SUCCESS => { |
| 1186 | const fd: posix.fd_t = @intCast(rc); |
| 1187 | errdefer posix.close(fd); |
| 1188 | if (!have_accept4) while (true) { |
| 1189 | try pool.checkCancel(); |
| 1190 | switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, posix.FD_CLOEXEC))) { |
| 1191 | .SUCCESS => break, |
| 1192 | .INTR => continue, |
| 1193 | else => |err| return posix.unexpectedErrno(err), |
| 1194 | } |
| 1195 | }; |
| 1196 | break fd; |
| 1197 | }, |
| 1198 | .INTR => continue, |
| 1199 | .AGAIN => |err| return errnoBug(err), |
| 1200 | .BADF => |err| return errnoBug(err), // always a race condition |
| 1201 | .CONNABORTED => return error.ConnectionAborted, |
| 1202 | .FAULT => |err| return errnoBug(err), |
| 1203 | .INVAL => return error.SocketNotListening, |
| 1204 | .NOTSOCK => |err| return errnoBug(err), |
| 1205 | .MFILE => return error.ProcessFdQuotaExceeded, |
| 1206 | .NFILE => return error.SystemFdQuotaExceeded, |
| 1207 | .NOBUFS => return error.SystemResources, |
| 1208 | .NOMEM => return error.SystemResources, |
| 1209 | .OPNOTSUPP => |err| return errnoBug(err), |
| 1210 | .PROTO => return error.ProtocolFailure, |
| 1211 | .PERM => return error.BlockedByFirewall, |
| 1212 | else => |err| return posix.unexpectedErrno(err), |
| 1213 | } |
| 1214 | }; |
| 1215 | return .{ .socket = .{ |
| 1216 | .handle = fd, |
| 1217 | .address = addressFromPosix(&storage), |
| 1218 | } }; |
| 1219 | } |
| 1220 | |
| 1040 | 1221 | fn netReadPosix(userdata: ?*anyopaque, stream: Io.net.Stream, data: [][]u8) Io.net.Stream.Reader.Error!usize { |
| 1041 | 1222 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1042 | 1223 | try pool.checkCancel(); |
| ... | ... | @@ -1052,11 +1233,41 @@ fn netReadPosix(userdata: ?*anyopaque, stream: Io.net.Stream, data: [][]u8) Io.n |
| 1052 | 1233 | } |
| 1053 | 1234 | const dest = iovecs_buffer[0..i]; |
| 1054 | 1235 | assert(dest[0].len > 0); |
| 1055 | | const n = try posix.readv(stream.handle, dest); |
| 1236 | const n = try posix.readv(stream.socket.handle, dest); |
| 1056 | 1237 | if (n == 0) return error.EndOfStream; |
| 1057 | 1238 | return n; |
| 1058 | 1239 | } |
| 1059 | 1240 | |
| 1241 | fn netSend( |
| 1242 | userdata: ?*anyopaque, |
| 1243 | handle: Io.net.Socket.Handle, |
| 1244 | address: Io.net.IpAddress, |
| 1245 | data: []const u8, |
| 1246 | ) Io.net.Socket.SendError!void { |
| 1247 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1248 | try pool.checkCancel(); |
| 1249 | |
| 1250 | _ = handle; |
| 1251 | _ = address; |
| 1252 | _ = data; |
| 1253 | @panic("TODO"); |
| 1254 | } |
| 1255 | |
| 1256 | fn netReceive( |
| 1257 | userdata: ?*anyopaque, |
| 1258 | handle: Io.net.Socket.Handle, |
| 1259 | address: Io.net.IpAddress, |
| 1260 | buffer: []u8, |
| 1261 | ) Io.net.Socket.ReceiveError!void { |
| 1262 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1263 | try pool.checkCancel(); |
| 1264 | |
| 1265 | _ = handle; |
| 1266 | _ = address; |
| 1267 | _ = buffer; |
| 1268 | @panic("TODO"); |
| 1269 | } |
| 1270 | |
| 1060 | 1271 | fn netWritePosix( |
| 1061 | 1272 | userdata: ?*anyopaque, |
| 1062 | 1273 | stream: Io.net.Stream, |
| ... | ... | @@ -1106,7 +1317,7 @@ fn netWritePosix( |
| 1106 | 1317 | }, |
| 1107 | 1318 | }; |
| 1108 | 1319 | const flags = posix.MSG.NOSIGNAL; |
| 1109 | | return posix.sendmsg(stream.handle, &msg, flags); |
| 1320 | return posix.sendmsg(stream.socket.handle, &msg, flags); |
| 1110 | 1321 | } |
| 1111 | 1322 | |
| 1112 | 1323 | fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { |
| ... | ... | @@ -1117,11 +1328,13 @@ fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), |
| 1117 | 1328 | i.* += 1; |
| 1118 | 1329 | } |
| 1119 | 1330 | |
| 1120 | | fn netClose(userdata: ?*anyopaque, stream: Io.net.Stream) void { |
| 1331 | fn netClose(userdata: ?*anyopaque, handle: Io.net.Socket.Handle) void { |
| 1121 | 1332 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1122 | 1333 | _ = pool; |
| 1123 | | const net_stream: std.net.Stream = .{ .handle = stream.handle }; |
| 1124 | | return net_stream.close(); |
| 1334 | switch (native_os) { |
| 1335 | .windows => windows.closesocket(handle) catch recoverableOsBugDetected(), |
| 1336 | else => posix.close(handle), |
| 1337 | } |
| 1125 | 1338 | } |
| 1126 | 1339 | |
| 1127 | 1340 | fn netInterfaceNameResolve( |
| ... | ... | @@ -1153,13 +1366,13 @@ fn netInterfaceNameResolve( |
| 1153 | 1366 | try pool.checkCancel(); |
| 1154 | 1367 | switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) { |
| 1155 | 1368 | .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) }, |
| 1156 | | .INVAL => |err| return badErrno(err), // Bad parameters. |
| 1157 | | .NOTTY => |err| return badErrno(err), |
| 1158 | | .NXIO => |err| return badErrno(err), |
| 1159 | | .BADF => |err| return badErrno(err), // Always a race condition. |
| 1160 | | .FAULT => |err| return badErrno(err), // Bad pointer parameter. |
| 1369 | .INVAL => |err| return errnoBug(err), // Bad parameters. |
| 1370 | .NOTTY => |err| return errnoBug(err), |
| 1371 | .NXIO => |err| return errnoBug(err), |
| 1372 | .BADF => |err| return errnoBug(err), // Always a race condition. |
| 1373 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. |
| 1161 | 1374 | .INTR => continue, |
| 1162 | | .IO => |err| return badErrno(err), // sock_fd is not a file descriptor |
| 1375 | .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor |
| 1163 | 1376 | .NODEV => return error.InterfaceNotFound, |
| 1164 | 1377 | else => |err| return posix.unexpectedErrno(err), |
| 1165 | 1378 | } |
| ... | ... | @@ -1207,8 +1420,8 @@ const PosixAddress = extern union { |
| 1207 | 1420 | in6: posix.sockaddr.in6, |
| 1208 | 1421 | }; |
| 1209 | 1422 | |
| 1210 | | fn posixAddressFamily(a: Io.net.IpAddress) posix.sa_family_t { |
| 1211 | | return switch (a) { |
| 1423 | fn posixAddressFamily(a: *const Io.net.IpAddress) posix.sa_family_t { |
| 1424 | return switch (a.*) { |
| 1212 | 1425 | .ip4 => posix.AF.INET, |
| 1213 | 1426 | .ip6 => posix.AF.INET6, |
| 1214 | 1427 | }; |
| ... | ... | @@ -1267,9 +1480,27 @@ fn address6ToPosix(a: Io.net.Ip6Address) posix.sockaddr.in6 { |
| 1267 | 1480 | }; |
| 1268 | 1481 | } |
| 1269 | 1482 | |
| 1270 | | fn badErrno(err: posix.E) Io.UnexpectedError { |
| 1483 | fn errnoBug(err: posix.E) Io.UnexpectedError { |
| 1271 | 1484 | switch (builtin.mode) { |
| 1272 | 1485 | .Debug => std.debug.panic("programmer bug caused syscall error: {t}", .{err}), |
| 1273 | 1486 | else => return error.Unexpected, |
| 1274 | 1487 | } |
| 1275 | 1488 | } |
| 1489 | |
| 1490 | fn posixSocketMode(mode: Io.net.Socket.Mode) u32 { |
| 1491 | return switch (mode) { |
| 1492 | .stream => posix.SOCK.STREAM, |
| 1493 | .dgram => posix.SOCK.DGRAM, |
| 1494 | .seqpacket => posix.SOCK.SEQPACKET, |
| 1495 | .raw => posix.SOCK.RAW, |
| 1496 | .rdm => posix.SOCK.RDM, |
| 1497 | }; |
| 1498 | } |
| 1499 | |
| 1500 | fn posixProtocol(protocol: ?Io.net.Protocol) u32 { |
| 1501 | return @intFromEnum(protocol orelse return 0); |
| 1502 | } |
| 1503 | |
| 1504 | fn recoverableOsBugDetected() void { |
| 1505 | if (builtin.mode == .Debug) unreachable; |
| 1506 | } |