From 9ac1386c10736bc249f3891f34f23424531917a5 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 14 Mar 2026 10:03:09 -0400 Subject: [PATCH] std.Io.Threaded: windows networking without ws2_32 --- ci/x86_64-windows-debug.ps1 | 2 +- ci/x86_64-windows-release.ps1 | 2 +- lib/std/Build/Watch.zig | 4 +- lib/std/Io.zig | 6 +- lib/std/Io/Dispatch.zig | 10 +- lib/std/Io/Kqueue.zig | 23 +- lib/std/Io/Reader.zig | 2 +- lib/std/Io/Threaded.zig | 2163 +++++++++---------- lib/std/Io/Threaded/test.zig | 6 +- lib/std/Io/Uring.zig | 21 +- lib/std/Io/net.zig | 122 +- lib/std/Io/net/HostName.zig | 1 + lib/std/Io/net/test.zig | 16 +- lib/std/Progress.zig | 2 + lib/std/Thread.zig | 8 +- lib/std/c.zig | 3 - lib/std/debug/SelfInfo/Windows.zig | 1 + lib/std/os/windows.zig | 991 ++++++++- lib/std/os/windows/ntdll.zig | 16 +- lib/std/os/windows/win32error.zig | 266 +++ lib/std/os/windows/ws2_32.zig | 1925 +---------------- lib/std/posix.zig | 39 +- test/standalone/coff_dwarf/build.zig | 3 - test/standalone/issue_5825/build.zig | 1 - test/standalone/mix_o_files/build.zig | 3 - test/standalone/shared_library/build.zig | 3 - test/standalone/test_obj_link_run/build.zig | 1 - test/standalone/windows_argv/build.zig | 2 - test/tests.zig | 1 - tools/incr-check.zig | 4 - 30 files changed, 2302 insertions(+), 3345 deletions(-) diff --git a/ci/x86_64-windows-debug.ps1 b/ci/x86_64-windows-debug.ps1 index d1031386c5..01cd5be244 100644 --- a/ci/x86_64-windows-debug.ps1 +++ b/ci/x86_64-windows-debug.ps1 @@ -85,7 +85,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\ CheckLastExitCode Write-Output "Build and run behavior tests with msvc..." -cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib +cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode .\behavior-x86_64-windows-msvc diff --git a/ci/x86_64-windows-release.ps1 b/ci/x86_64-windows-release.ps1 index e24432e076..38458c9883 100644 --- a/ci/x86_64-windows-release.ps1 +++ b/ci/x86_64-windows-release.ps1 @@ -104,7 +104,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\ CheckLastExitCode Write-Output "Build and run behavior tests with msvc..." -cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib +cl /I..\lib /W3 /Z7 behavior-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /link /nologo /debug /subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode .\behavior-x86_64-windows-msvc diff --git a/lib/std/Build/Watch.zig b/lib/std/Build/Watch.zig index fe0a532395..25dbc4d364 100644 --- a/lib/std/Build/Watch.zig +++ b/lib/std/Build/Watch.zig @@ -354,7 +354,7 @@ const Os = switch (builtin.os.tag) { } } - fn notifyApc(apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows.ULONG) callconv(.winapi) void { + fn notifyApc(apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows.ULONG) align(std.Io.Threaded.apc_align) callconv(.winapi) void { const w: *Watch = @ptrCast(@alignCast(apc_context)); const dir: *Directory = @fieldParentPtr("iosb", iosb); assert(iosb.u.Status != .PENDING); @@ -369,7 +369,7 @@ const Os = switch (builtin.os.tag) { var dir_handle: windows.HANDLE = undefined; const root_fd = path.root_dir.handle.handle; const sub_path = path.subPathOrDot(); - const sub_path_w = try Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path); // TODO eliminate this call + const sub_path_w = try Io.Threaded.sliceToPrefixedFileW(root_fd, sub_path, .{}); // TODO eliminate this call var iosb: windows.IO_STATUS_BLOCK = undefined; switch (windows.ntdll.NtCreateFile( &dir_handle, diff --git a/lib/std/Io.zig b/lib/std/Io.zig index e191e52eb9..fb06db6fdb 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -235,10 +235,10 @@ pub const VTable = struct { random: *const fn (?*anyopaque, buffer: []u8) void, randomSecure: *const fn (?*anyopaque, buffer: []u8) RandomSecureError!void, - netListenIp: *const fn (?*anyopaque, address: net.IpAddress, net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, - netAccept: *const fn (?*anyopaque, server: net.Socket.Handle) net.Server.AcceptError!net.Stream, + netListenIp: *const fn (?*anyopaque, address: *const net.IpAddress, net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Socket, + netAccept: *const fn (?*anyopaque, server: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket, netBindIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket, - netConnectIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream, + netConnectIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket, netListenUnix: *const fn (?*anyopaque, *const net.UnixAddress, net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle, netConnectUnix: *const fn (?*anyopaque, *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle, netSocketCreatePair: *const fn (?*anyopaque, net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket, diff --git a/lib/std/Io/Dispatch.zig b/lib/std/Io/Dispatch.zig index 615e77f2ca..76e23d6818 100644 --- a/lib/std/Io/Dispatch.zig +++ b/lib/std/Io/Dispatch.zig @@ -4784,9 +4784,9 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void { fn netListenIpUnavailable( userdata: ?*anyopaque, - address: net.IpAddress, + address: *const net.IpAddress, options: net.IpAddress.ListenOptions, -) net.IpAddress.ListenError!net.Server { +) net.IpAddress.ListenError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = address; @@ -4797,10 +4797,12 @@ fn netListenIpUnavailable( fn netAcceptUnavailable( userdata: ?*anyopaque, listen_handle: net.Socket.Handle, -) net.Server.AcceptError!net.Stream { + options: net.Server.AcceptOptions, +) net.Server.AcceptError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = listen_handle; + _ = options; return error.NetworkDown; } @@ -4820,7 +4822,7 @@ fn netConnectIpUnavailable( userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions, -) net.IpAddress.ConnectError!net.Stream { +) net.IpAddress.ConnectError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = address; diff --git a/lib/std/Io/Kqueue.zig b/lib/std/Io/Kqueue.zig index 3a4dadea2c..b3645b0568 100644 --- a/lib/std/Io/Kqueue.zig +++ b/lib/std/Io/Kqueue.zig @@ -13,6 +13,7 @@ const IpAddress = std.Io.net.IpAddress; const errnoBug = std.Io.Threaded.errnoBug; const closeFd = std.Io.Threaded.closeFd; const posix = std.posix; +const posixSocketModeProtocol = Io.Threaded.posixSocketModeProtocol; /// Must be a thread-safe allocator. gpa: Allocator, @@ -1000,19 +1001,20 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { fn netListenIp( userdata: ?*anyopaque, - address: net.IpAddress, + address: *const net.IpAddress, options: net.IpAddress.ListenOptions, -) net.IpAddress.ListenError!net.Server { +) net.IpAddress.ListenError!net.Socket { const k: *Kqueue = @ptrCast(@alignCast(userdata)); _ = k; _ = address; _ = options; @panic("TODO"); } -fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle) net.Server.AcceptError!net.Stream { +fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket { const k: *Kqueue = @ptrCast(@alignCast(userdata)); _ = k; _ = server; + _ = options; @panic("TODO"); } fn netBindIp( @@ -1028,12 +1030,9 @@ fn netBindIp( var addr_len = Io.Threaded.addressToPosix(address, &storage); try posixBind(k, socket_fd, &storage.any, addr_len); try posixGetSockName(k, socket_fd, &storage.any, &addr_len); - return .{ - .handle = socket_fd, - .address = Io.Threaded.addressFromPosix(&storage), - }; + return .{ .handle = socket_fd, .address = Io.Threaded.addressFromPosix(&storage) }; } -fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream { +fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket { if (options.timeout != .none) @panic("TODO"); const k: *Kqueue = @ptrCast(@alignCast(userdata)); const family = Io.Threaded.posixAddressFamily(address); @@ -1046,10 +1045,7 @@ fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: n var addr_len = Io.Threaded.addressToPosix(address, &storage); try posixConnect(k, socket_fd, &storage.any, addr_len); try posixGetSockName(k, socket_fd, &storage.any, &addr_len); - return .{ .socket = .{ - .handle = socket_fd, - .address = Io.Threaded.addressFromPosix(&storage), - } }; + return .{ .handle = socket_fd, .address = Io.Threaded.addressFromPosix(&storage) }; } fn posixConnect(k: *Kqueue, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void { @@ -1345,8 +1341,7 @@ fn openSocketPosix( Unexpected, Canceled, }!posix.socket_t { - const mode = Io.Threaded.posixSocketMode(options.mode); - const protocol = Io.Threaded.posixProtocol(options.protocol); + const mode, const protocol = try posixSocketModeProtocol(family, options.mode, options.protocol); const socket_fd = while (true) { try k.checkCancel(); const flags: u32 = mode | if (Io.Threaded.socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC; diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index 26ab1cea35..9f303e824c 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -1997,7 +1997,7 @@ pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const pub fn writableVectorWsa( r: *Reader, - buffer: []std.os.windows.ws2_32.WSABUF, + buffer: []std.os.windows.AFD.WSABUF(.@"var"), data: []const []u8, ) Error!struct { usize, usize } { var i: usize = 0; diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 6ef8d5d7f5..54d2ed79af 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -11,8 +11,8 @@ const Io = std.Io; const net = std.Io.net; const File = std.Io.File; const Dir = std.Io.Dir; -const HostName = std.Io.net.HostName; -const IpAddress = std.Io.net.IpAddress; +const HostName = net.HostName; +const IpAddress = net.IpAddress; const process = std.process; const Allocator = std.mem.Allocator; const Alignment = std.mem.Alignment; @@ -47,8 +47,6 @@ busy_count: usize = 0, worker_threads: std.atomic.Value(?*Thread), pid: Pid = .unknown, -wsa: if (is_windows) Wsa else struct {} = .{}, - have_signal_handler: bool, old_sig_io: if (have_sig_io) posix.Sigaction else void, old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void, @@ -77,6 +75,8 @@ argv0: Argv0, environ_initialized: bool, environ: Environ, +dl: Dl = .init, + null_file: NullFile = .{}, random_file: RandomFile = .{}, pipe_file: PipeFile = .{}, @@ -90,6 +90,67 @@ const SystemBasicInformation = if (!is_windows) struct {} else struct { initialized: std.atomic.Value(bool) = .{ .raw = false }, }; +const Dl = switch (native_os) { + .windows => struct { + iphlpapi_dll: std.atomic.Value(?*anyopaque), + ConvertInterfaceNameToLuidW: std.atomic.Value(?*const fn ( + InterfaceName: [*:0]const windows.WCHAR, + InterfaceLuid: *windows.NET.LUID, + ) callconv(.winapi) windows.Win32Error), + ConvertInterfaceLuidToIndex: std.atomic.Value(?*const fn ( + InterfaceLuid: *const windows.NET.LUID, + InterfaceIndex: *windows.NET.IFINDEX, + ) callconv(.winapi) windows.Win32Error), + ConvertInterfaceIndexToLuid: std.atomic.Value(?*const fn ( + InterfaceIndex: std.os.windows.NET.IFINDEX, + InterfaceLuid: *std.os.windows.NET.LUID, + ) callconv(.winapi) windows.Win32Error), + ConvertInterfaceLuidToNameW: std.atomic.Value(?*const fn ( + InterfaceLuid: *const std.os.windows.NET.LUID, + InterfaceName: std.os.windows.PWSTR, + Length: std.os.windows.SIZE_T, + ) callconv(.winapi) std.os.windows.Win32Error), + + dnsapi_dll: std.atomic.Value(?*anyopaque), + DnsQueryEx: std.atomic.Value(?*const fn ( + pQueryRequest: *const windows.DNS.QUERY.REQUEST, + pQueryResults: *windows.DNS.QUERY.RESULT, + pCancelHandle: ?*windows.DNS.QUERY.CANCEL, + ) callconv(.winapi) windows.DNS.STATUS), + //DnsCancelQuery: std.atomic.Value(?*const fn ( + // pCancelHandle: *const windows.DNS.QUERY.CANCEL, + //) callconv(.winapi) windows.DNS.STATUS), + DnsFree: std.atomic.Value(?*const fn ( + pRecordList: ?*anyopaque, + FreeType: windows.DNS.FREE_TYPE, + ) callconv(.winapi) void), + + const init: Dl = .{ + .iphlpapi_dll = .init(null), + .ConvertInterfaceNameToLuidW = .init(null), + .ConvertInterfaceLuidToIndex = .init(null), + .ConvertInterfaceIndexToLuid = .init(null), + .ConvertInterfaceLuidToNameW = .init(null), + + .dnsapi_dll = .init(null), + .DnsQueryEx = .init(null), + //.DnsCancelQuery = .init(null), + .DnsFree = .init(null), + }; + fn deinit(dl: *Dl) void { + if (dl.iphlpapi_dll.raw) |iphlpapi_dll| switch (windows.ntdll.LdrUnloadDll(iphlpapi_dll)) { + .SUCCESS => {}, + else => |status| windows.unexpectedStatus(status) catch {}, + }; + dl.* = .init; + } + }, + else => struct { + const init: Dl = .{}; + fn deinit(_: Dl) void {} + }, +}; + pub const Csprng = struct { rng: std.Random.DefaultCsprng, @@ -375,6 +436,17 @@ pub const UseFchmodat2 = if (have_fchmodat2 and !have_fchmodat_flags) enum { pub const default: UseFchmodat2 = .disabled; }; +pub const apc_align = @max(default_fn_align, 2); + +const default_fn_align = switch (builtin.mode) { + .Debug, .ReleaseSafe, .ReleaseFast => switch (builtin.cpu.arch) { + else => |arch| @compileError("Unsupported architecture: " ++ @tagName(arch)), + .arm, .thumb => 4, + .aarch64, .x86, .x86_64 => 16, + }, + .ReleaseSmall => 1, +}; + const Runnable = struct { node: std.SinglyLinkedList.Node, startFn: *const fn (*Runnable, *Thread, *Threaded) void, @@ -1496,18 +1568,6 @@ const AlertableSyscall = struct { s.finish(); return windows.unexpectedStatus(status); } - - fn unexpectedWsaError(s: AlertableSyscall, err: ws2_32.WinsockError) Io.UnexpectedError { - @branchHint(.cold); - s.finish(); - return windows.unexpectedWsaError(err); - } - - fn wsaErrorBug(s: AlertableSyscall, err: ws2_32.WinsockError) Io.UnexpectedError { - @branchHint(.cold); - s.finish(); - return windows.wsaErrorBug(err); - } }; pub fn waitForApcOrAlert() void { @@ -1667,13 +1727,11 @@ pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void { pub fn deinit(t: *Threaded) void { t.join(); - if (is_windows and t.wsa.status == .initialized) { - if (ws2_32.WSACleanup() != 0) recoverableOsBugDetected(); - } if (posix.Sigaction != void and t.have_signal_handler) { if (have_sig_io) posix.sigaction(.IO, &t.old_sig_io, null); if (have_sig_pipe) posix.sigaction(.PIPE, &t.old_sig_pipe, null); } + t.dl.deinit(); t.null_file.deinit(); t.random_file.deinit(); t.pipe_file.deinit(); @@ -1717,6 +1775,7 @@ fn worker(t: *Threaded) void { .SPECIFIC = .{ .THREAD = .{ .TERMINATE = true, // for `NtCancelSynchronousIoFile` + .ALERT = true, // for `NtAlertThread` }, }, }, @@ -2914,7 +2973,7 @@ fn batchApc( apc_context: ?*anyopaque, iosb: *windows.IO_STATUS_BLOCK, _: windows.ULONG, -) callconv(.winapi) void { +) align(apc_align) callconv(.winapi) void { const b: *Io.Batch = @ptrCast(@alignCast(apc_context)); const operation_userdata: *WindowsBatchOperationUserdata = @fieldParentPtr("iosb", iosb); const erased_userdata = operation_userdata.toErased(); @@ -3278,7 +3337,7 @@ fn dirCreateDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, pe _ = t; _ = permissions; // TODO use this value - const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const attr: windows.OBJECT.ATTRIBUTES = .{ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, .Attributes = .{ .INHERIT = false }, @@ -3446,7 +3505,7 @@ fn dirCreateDirPathOpenWindows( }; components: while (true) { - const sub_path_w = try sliceToPrefixedFileW(dir.handle, component.path); + const sub_path_w = try sliceToPrefixedFileW(dir.handle, component.path, .{}); const attr: windows.OBJECT.ATTRIBUTES = .{ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, .ObjectName = @constCast(&sub_path_w.string()), @@ -4144,7 +4203,7 @@ fn dirAccessWindows( _ = options; // TODO if (std.mem.eql(u8, sub_path, ".") or std.mem.eql(u8, sub_path, "..")) return; - const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const attr: windows.OBJECT.ATTRIBUTES = .{ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, .ObjectName = @constCast(&sub_path_w.string()), @@ -4353,7 +4412,7 @@ fn dirCreateFileWindows( if (std.mem.eql(u8, sub_path, ".")) return error.IsDir; if (std.mem.eql(u8, sub_path, "..")) return error.IsDir; - const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const attr: windows.OBJECT.ATTRIBUTES = .{ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, .ObjectName = @constCast(&sub_path_w.string()), @@ -4943,7 +5002,7 @@ fn dirOpenFileWindows( ) File.OpenError!File { const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path); + const sub_path_w_array = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const sub_path_w = sub_path_w_array.span(); const dir_handle = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle; return dirOpenFileWtf16(dir_handle, sub_path_w, flags); @@ -5197,7 +5256,7 @@ fn dirOpenDirPosix( _ = t; if (is_windows) { - const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + const sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); return dirOpenDirWindows(dir, sub_path_w.span(), options); } @@ -6027,7 +6086,7 @@ fn dirRealPathFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - var path_name_w = try sliceToPrefixedFileW(dir.handle, sub_path); + var path_name_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const h_file = handle: { if (OpenFile(path_name_w.span(), .{ @@ -6182,6 +6241,7 @@ pub fn GetFinalPathNameByHandle( .out = &output_buf, })).u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, else => |status| return windows.unexpectedStatus(status), } @@ -6241,6 +6301,7 @@ pub fn GetFinalPathNameByHandle( .out = &vol_output_buf, })).u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, .UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume, else => |status| return windows.unexpectedStatus(status), } @@ -6383,6 +6444,10 @@ const Wtf16ToPrefixedFileWError = error{ FileNotFound, } || Dir.PathNameError || Io.Cancelable || Io.UnexpectedError; +const Wtf16ToPrefixedFileWOptions = struct { + allow_relative: bool = true, +}; + /// Converts the `path` to WTF16, null-terminated. If the path contains any /// namespace prefix, or is anything but a relative path (rooted, drive relative, /// etc) the result will have the NT-style prefix `\??\`. @@ -6394,7 +6459,7 @@ const Wtf16ToPrefixedFileWError = error{ /// is non-null, or the CWD if it is null. /// - Special case device names like COM1, NUL, etc are not handled specially (TODO) /// - . and space are not stripped from the end of relative paths (potential TODO) -pub fn wToPrefixedFileW(dir: ?windows.HANDLE, path: [:0]const u16) Wtf16ToPrefixedFileWError!WindowsPathSpace { +pub fn wToPrefixedFileW(dir: ?windows.HANDLE, path: [:0]const u16, options: Wtf16ToPrefixedFileWOptions) Wtf16ToPrefixedFileWError!WindowsPathSpace { const nt_prefix = [_]u16{ '\\', '?', '?', '\\' }; if (windows.hasCommonNtPrefix(u16, path)) { // TODO: Figure out a way to design an API that can avoid the copy for NT, @@ -6409,58 +6474,54 @@ pub fn wToPrefixedFileW(dir: ?windows.HANDLE, path: [:0]const u16) Wtf16ToPrefix } else { const path_type = Dir.path.getWin32PathType(u16, path); var path_space: WindowsPathSpace = undefined; - if (path_type == .local_device) { - switch (getLocalDevicePathType(u16, path)) { - .verbatim => { - path_space.data[0..nt_prefix.len].* = nt_prefix; - const len_after_prefix = path.len - nt_prefix.len; - @memcpy(path_space.data[nt_prefix.len..][0..len_after_prefix], path[nt_prefix.len..]); - path_space.len = path.len; - path_space.data[path_space.len] = 0; - return path_space; - }, - .local_device, .fake_verbatim => { - const path_byte_len = windows.ntdll.RtlGetFullPathName_U( - path.ptr, - path_space.data.len * 2, - &path_space.data, - null, - ); - if (path_byte_len == 0) { - // TODO: This may not be the right error - return error.BadPathName; - } else if (path_byte_len / 2 > path_space.data.len) { - return error.NameTooLong; - } - path_space.len = path_byte_len / 2; - // Both prefixes will be normalized but retained, so all - // we need to do now is replace them with the NT prefix - path_space.data[0..nt_prefix.len].* = nt_prefix; - return path_space; - }, - } - } - relative: { - if (path_type == .relative) { - // TODO: Handle special case device names like COM1, AUX, NUL, CONIN$, CONOUT$, etc. - // See https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html - - // TODO: Potentially strip all trailing . and space characters from the - // end of the path. This is something that both RtlDosPathNameToNtPathName_U - // and RtlGetFullPathName_U do. Technically, trailing . and spaces - // are allowed, but such paths may not interact well with Windows (i.e. - // files with these paths can't be deleted from explorer.exe, etc). - // This could be something that normalizePath may want to do. - - @memcpy(path_space.data[0..path.len], path); - // Try to normalize, but if we get too many parent directories, - // then we need to start over and use RtlGetFullPathName_U instead. - path_space.len = windows.normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) { - error.TooManyParentDirs => break :relative, - }; + if (path_type == .local_device) switch (getLocalDevicePathType(u16, path)) { + .verbatim => { + path_space.data[0..nt_prefix.len].* = nt_prefix; + const len_after_prefix = path.len - nt_prefix.len; + @memcpy(path_space.data[nt_prefix.len..][0..len_after_prefix], path[nt_prefix.len..]); + path_space.len = path.len; path_space.data[path_space.len] = 0; return path_space; - } + }, + .local_device, .fake_verbatim => { + const path_byte_len = windows.ntdll.RtlGetFullPathName_U( + path.ptr, + path_space.data.len * 2, + &path_space.data, + null, + ); + if (path_byte_len == 0) { + // TODO: This may not be the right error + return error.BadPathName; + } else if (path_byte_len / 2 > path_space.data.len) { + return error.NameTooLong; + } + path_space.len = path_byte_len / 2; + // Both prefixes will be normalized but retained, so all + // we need to do now is replace them with the NT prefix + path_space.data[0..nt_prefix.len].* = nt_prefix; + return path_space; + }, + }; + if (options.allow_relative and path_type == .relative) relative: { + // TODO: Handle special case device names like COM1, AUX, NUL, CONIN$, CONOUT$, etc. + // See https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + + // TODO: Potentially strip all trailing . and space characters from the + // end of the path. This is something that both RtlDosPathNameToNtPathName_U + // and RtlGetFullPathName_U do. Technically, trailing . and spaces + // are allowed, but such paths may not interact well with Windows (i.e. + // files with these paths can't be deleted from explorer.exe, etc). + // This could be something that normalizePath may want to do. + + @memcpy(path_space.data[0..path.len], path); + // Try to normalize, but if we get too many parent directories, + // then we need to start over and use RtlGetFullPathName_U instead. + path_space.len = windows.normalizePath(u16, path_space.data[0..path.len]) catch |err| switch (err) { + error.TooManyParentDirs => break :relative, + }; + path_space.data[path_space.len] = 0; + return path_space; } // We now know we are going to return an absolute NT path, so // we can unconditionally prefix it with the NT prefix. @@ -6591,13 +6652,13 @@ pub const Wtf8ToPrefixedFileWError = Wtf16ToPrefixedFileWError; /// Same as `wToPrefixedFileW` but accepts a WTF-8 encoded path. /// https://wtf-8.codeberg.page/ -pub fn sliceToPrefixedFileW(dir: ?windows.HANDLE, path: []const u8) Wtf8ToPrefixedFileWError!WindowsPathSpace { +pub fn sliceToPrefixedFileW(dir: ?windows.HANDLE, path: []const u8, options: Wtf16ToPrefixedFileWOptions) Wtf8ToPrefixedFileWError!WindowsPathSpace { var temp_path: WindowsPathSpace = undefined; temp_path.len = std.unicode.wtf8ToWtf16Le(&temp_path.data, path) catch |err| switch (err) { error.InvalidWtf8 => return error.BadPathName, }; temp_path.data[temp_path.len] = 0; - return wToPrefixedFileW(dir, temp_path.span()); + return wToPrefixedFileW(dir, temp_path.span(), options); } pub const WindowsPathSpace = struct { @@ -7068,7 +7129,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov // Can't remove the parent directory with an open handle. return error.FileBusy; } - var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); if (std.mem.eql(u8, sub_path, ".")) { // Windows does not recognize this, but it does work with empty string. sub_path_w.len = 0; @@ -7336,9 +7397,9 @@ fn dirRenameWindowsInner( replace_if_exists: bool, ) Dir.RenamePreserveError!void { const w = windows; - const old_path_w_buf = try sliceToPrefixedFileW(old_dir.handle, old_sub_path); + const old_path_w_buf = try sliceToPrefixedFileW(old_dir.handle, old_sub_path, .{}); const old_path_w = old_path_w_buf.span(); - const new_path_w_buf = try sliceToPrefixedFileW(new_dir.handle, new_sub_path); + const new_path_w_buf = try sliceToPrefixedFileW(new_dir.handle, new_sub_path, .{}); const new_path_w = new_path_w_buf.span(); const src_fd = src_fd: { @@ -7673,7 +7734,7 @@ fn dirSymLinkWindows( std.mem.nativeToLittle(u16, '\\'), ); - const sym_link_path_w = try sliceToPrefixedFileW(dir.handle, sym_link_path); + const sym_link_path_w = try sliceToPrefixedFileW(dir.handle, sym_link_path, .{}); const SYMLINK_DATA = extern struct { ReparseTag: w.IO_REPARSE_TAG, @@ -7738,7 +7799,7 @@ fn dirSymLinkWindows( break :target_path target_path_w.span(), } } - var prefixed_target_path = try wToPrefixedFileW(dir.handle, target_path_w.span()); + var prefixed_target_path = try wToPrefixedFileW(dir.handle, target_path_w.span(), .{}); // We do this after prefixing to ensure that drive-relative paths are treated as absolute is_target_absolute = Dir.path.isAbsoluteWindowsWtf16(prefixed_target_path.span()); break :target_path prefixed_target_path.span(); @@ -7770,6 +7831,8 @@ fn dirSymLinkWindows( .in = buffer[0..buf_len], })).u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, .PRIVILEGE_NOT_HELD => return error.PermissionDenied, .ACCESS_DENIED => return error.AccessDenied, .INVALID_DEVICE_REQUEST => return error.FileSystem, @@ -7887,7 +7950,7 @@ fn dirReadLink(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: [] fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize { // This gets used once for `sub_path` and then reused again temporarily // before converting back to `buffer`. - var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path); + var sub_path_w = try sliceToPrefixedFileW(dir.handle, sub_path, .{}); const attr: windows.OBJECT.ATTRIBUTES = .{ .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w.span())) null else dir.handle, .ObjectName = @constCast(&sub_path_w.string()), @@ -8532,6 +8595,7 @@ fn isTty(file: File) Io.Cancelable!bool { .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), })).u.Status) { .SUCCESS => return true, + .CANCELLED => unreachable, .INVALID_HANDLE => return isCygwinPty(file), else => return false, } @@ -8618,6 +8682,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), })).u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, .INVALID_HANDLE => return if (!try isCygwinPty(file)) error.NotTerminalDevice, else => return error.NotTerminalDevice, } @@ -8644,6 +8709,7 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE .in = @ptrCast(&set_console_mode.request(file, 0, .{}, 0, .{})), })).u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, else => |status| return windows.unexpectedStatus(status), } } @@ -8667,6 +8733,7 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool { })).u.Status) { .SUCCESS => if (get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0) return true, + .CANCELLED => unreachable, .INVALID_HANDLE => return isCygwinPty(file), else => return false, } @@ -9673,7 +9740,7 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingEr return ntReadFileResult(&iosb); } -fn flagApc(userdata: ?*anyopaque, _: *windows.IO_STATUS_BLOCK, _: windows.ULONG) callconv(.winapi) void { +fn flagApc(userdata: ?*anyopaque, _: *windows.IO_STATUS_BLOCK, _: windows.ULONG) align(apc_align) callconv(.winapi) void { const flag: *bool = @ptrCast(userdata); flag.* = true; } @@ -10157,7 +10224,7 @@ fn processExecutableOpen(userdata: ?*anyopaque, flags: File.OpenFlags) process.O // not the path that the symlink points to. However, because we are opening // the file, we can let the openFileW call follow the symlink for us. const image_path_name = windows.peb().ProcessParameters.ImagePathName.sliceZ(); - const prefixed_path_w = try wToPrefixedFileW(null, image_path_name); + const prefixed_path_w = try wToPrefixedFileW(null, image_path_name, .{}); return dirOpenFileWtf16(null, prefixed_path_w.span(), flags); }, .driverkit, @@ -10364,6 +10431,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut var path_name_w_buf = try wToPrefixedFileW( null, windows.peb().ProcessParameters.ImagePathName.sliceZ(), + .{}, ); const h_file = handle: { @@ -11177,22 +11245,6 @@ fn netWriteFile( @panic("TODO implement netWriteFile"); } -fn netWriteFileUnavailable( - userdata: ?*anyopaque, - socket_handle: net.Socket.Handle, - header: []const u8, - file_reader: *File.Reader, - limit: Io.Limit, -) net.Stream.Writer.WriteFileError!usize { - const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; - _ = socket_handle; - _ = header; - _ = file_reader; - _ = limit; - return error.NetworkDown; -} - fn fileWriteFilePositional( userdata: ?*anyopaque, file: File, @@ -11635,27 +11687,24 @@ fn sleepNanosleep(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void { fn netListenIpPosix( userdata: ?*anyopaque, - address: IpAddress, + address: *const IpAddress, options: IpAddress.ListenOptions, -) IpAddress.ListenError!net.Server { +) IpAddress.ListenError!net.Socket { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - const family = posixAddressFamily(&address); - const socket_fd = try openSocketPosix(family, .{ - .mode = options.mode, - .protocol = options.protocol, - }); + const family = posixAddressFamily(address); + const socket_fd = try openSocketPosix(family, .{ .mode = options.mode, .protocol = options.protocol }); errdefer closeFd(socket_fd); if (options.reuse_address) { - try setSocketOption(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1); + try setSocketOptionPosix(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1); if (@hasDecl(posix.SO, "REUSEPORT")) - try setSocketOption(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1); + try setSocketOptionPosix(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1); } var storage: PosixAddress = undefined; - var addr_len = addressToPosix(&address, &storage); + var addr_len = addressToPosix(address, &storage); try posixBind(socket_fd, &storage.any, addr_len); const syscall: Syscall = try .start(); @@ -11676,112 +11725,37 @@ fn netListenIpPosix( } try posixGetSockName(socket_fd, &storage.any, &addr_len); - return .{ - .socket = .{ - .handle = socket_fd, - .address = addressFromPosix(&storage), - }, - }; + return .{ .handle = socket_fd, .address = addressFromPosix(&storage) }; } fn netListenIpWindows( userdata: ?*anyopaque, - address: IpAddress, + address: *const IpAddress, options: IpAddress.ListenOptions, -) IpAddress.ListenError!net.Server { +) IpAddress.ListenError!net.Socket { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); - const family = posixAddressFamily(&address); - const socket_handle = try openSocketWsa(t, family, .{ - .mode = options.mode, - .protocol = options.protocol, - }); - errdefer closeSocketWindows(socket_handle); - - if (options.reuse_address) - try setSocketOptionWsa(t, socket_handle, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1); - - var storage: WsaAddress = undefined; - var addr_len = addressToWsa(&address, &storage); - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.bind(socket_handle, &storage.any, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .EADDRINUSE => return syscall.fail(error.AddressInUse), - .EADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .ENOBUFS => return syscall.fail(error.SystemResources), - .ENETDOWN => return syscall.fail(error.NetworkDown), - else => |err| return syscall.unexpectedWsaError(err), - } + _ = t; + const family = posixAddressFamily(address); + const socket_handle = try openSocketAfd(family, .{ .mode = options.mode, .protocol = options.protocol }); + errdefer windows.CloseHandle(socket_handle); + if (options.reuse_address) try setSocketOptionAfd(socket_handle, ws2_32.SOL.SOCKET, ws2_32.SO.REUSEADDR, true); + const bound_address = try bindSocketIpAfd(socket_handle, address, .Passive); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.START_LISTEN, + .in = @ptrCast(&windows.AFD.LISTEN_INFO{ + .UseSAN = windows.FALSE, + .MaximumConnectionQueue = options.kernel_backlog, + .UseDelayedAcceptance = windows.FALSE, + }), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } - - syscall = try .start(); - while (true) { - const rc = ws2_32.listen(socket_handle, options.kernel_backlog); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .ENETDOWN => return syscall.fail(error.NetworkDown), - .EADDRINUSE => return syscall.fail(error.AddressInUse), - .EMFILE, .ENOBUFS => return syscall.fail(error.SystemResources), - .EISCONN => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EOPNOTSUPP => |err| return syscall.wsaErrorBug(err), - .EINPROGRESS => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } - } - - try wsaGetSockName(t, socket_handle, &storage.any, &addr_len); - - return .{ - .socket = .{ - .handle = socket_handle, - .address = addressFromWsa(&storage), - }, - }; -} - -fn netListenIpUnavailable( - userdata: ?*anyopaque, - address: IpAddress, - options: IpAddress.ListenOptions, -) IpAddress.ListenError!net.Server { - _ = userdata; - _ = address; - _ = options; - return error.NetworkDown; + return .{ .handle = socket_handle, .address = bound_address }; } fn netListenUnixPosix( @@ -11833,85 +11807,40 @@ fn netListenUnixWindows( if (!net.has_unix_sockets) return error.AddressFamilyUnsupported; if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); - - const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) { + _ = t; + const is_abstract = address.isAbstract(); + const wps = if (!is_abstract) sliceToPrefixedFileW(null, address.path, .{ + .allow_relative = false, + }) catch |err| switch (err) { + error.NameTooLong, error.BadPathName => return error.AddressUnavailable, + else => |e| return e, + } else undefined; + const socket_handle = openSocketAfd(ws2_32.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) { error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported, else => |e| return e, }; - errdefer closeSocketWindows(socket_handle); - - var storage: WsaAddress = undefined; - const addr_len = addressUnixToWsa(address, &storage); - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.bind(socket_handle, &storage.any, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .EADDRINUSE => return syscall.fail(error.AddressInUse), - .EADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable), - .ENOBUFS => return syscall.fail(error.SystemResources), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + errdefer windows.CloseHandle(socket_handle); + if (!is_abstract) try socketOptionAfd(socket_handle, .special, 0, ws2_32.SO.UNIX_PATH, @constCast( + @as([]const u8, @ptrCast(&windows.AFD.SOCKOPT_INFO.UNIX_PATH{ + .Path = wps.data, + }))[0 .. @offsetOf(windows.AFD.SOCKOPT_INFO.UNIX_PATH, "Path") + @sizeOf(windows.WCHAR) * wps.len], + )); + try bindSocketUnixAfd(socket_handle, address); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.START_LISTEN, + .in = @ptrCast(&windows.AFD.LISTEN_INFO{ + .UseSAN = windows.FALSE, + .MaximumConnectionQueue = options.kernel_backlog, + .UseDelayedAcceptance = windows.FALSE, + }), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } - - syscall = try .start(); - while (true) { - const rc = ws2_32.listen(socket_handle, options.kernel_backlog); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return socket_handle; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ENETDOWN => return syscall.fail(error.NetworkDown), - .EADDRINUSE => return syscall.fail(error.AddressInUse), - .EMFILE, .ENOBUFS => return syscall.fail(error.SystemResources), - .EISCONN => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EOPNOTSUPP => |err| return syscall.wsaErrorBug(err), - .EINPROGRESS => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } - } -} - -fn netListenUnixUnavailable( - userdata: ?*anyopaque, - address: *const net.UnixAddress, - options: net.UnixAddress.ListenOptions, -) net.UnixAddress.ListenError!net.Socket.Handle { - _ = userdata; - _ = address; - _ = options; - return error.AddressFamilyUnsupported; + return socket_handle; } fn posixBindUnix( @@ -12103,40 +12032,7 @@ fn posixGetSockName( } } -fn wsaGetSockName( - t: *Threaded, - handle: ws2_32.SOCKET, - addr: *ws2_32.sockaddr, - addr_len: *i32, -) !void { - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.getsockname(handle, addr, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ENETDOWN => return syscall.fail(error.NetworkDown), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } - } -} - -fn setSocketOption(fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void { +fn setSocketOptionPosix(fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void { const o: []const u8 = @ptrCast(&option); const syscall: Syscall = try .start(); while (true) { @@ -12163,32 +12059,26 @@ fn setSocketOption(fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void } } -fn setSocketOptionWsa(t: *Threaded, socket: Io.net.Socket.Handle, level: i32, opt_name: u32, option: u32) !void { - const o: []const u8 = @ptrCast(&option); - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.setsockopt(socket, level, @bitCast(opt_name), o.ptr, @intCast(o.len)); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ENETDOWN => return syscall.fail(error.NetworkDown), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } +fn setSocketOptionAfd(socket: net.Socket.Handle, level: i32, opt_name: u32, opt_val: anytype) !void { + try socketOptionAfd(socket, .set, level, opt_name, @ptrCast(@constCast(&opt_val))); +} + +fn socketOptionAfd(socket: net.Socket.Handle, mode: windows.AFD.SOCKOPT_INFO.Mode, level: i32, opt_name: u32, opt_val: []u8) !void { + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.SOCKOPT, + .in = @ptrCast(&windows.AFD.SOCKOPT_INFO{ + .mode = mode, + .level = level, + .optname = opt_name, + .optval = opt_val.ptr, + .optlen = opt_val.len, + }), + })).u.Status) { + .SUCCESS => return, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } } @@ -12196,98 +12086,55 @@ fn netConnectIpPosix( userdata: ?*anyopaque, address: *const IpAddress, options: IpAddress.ConnectOptions, -) IpAddress.ConnectError!net.Stream { +) IpAddress.ConnectError!net.Socket { if (!have_networking) return error.NetworkDown; if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout"); const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; const family = posixAddressFamily(address); - const socket_fd = try openSocketPosix(family, .{ - .mode = options.mode, - .protocol = options.protocol, - }); + const socket_fd = try openSocketPosix(family, .{ .mode = options.mode, .protocol = options.protocol }); errdefer closeFd(socket_fd); var storage: PosixAddress = undefined; var addr_len = addressToPosix(address, &storage); try posixConnect(socket_fd, &storage.any, addr_len); try posixGetSockName(socket_fd, &storage.any, &addr_len); - return .{ .socket = .{ - .handle = socket_fd, - .address = addressFromPosix(&storage), - } }; + return .{ .handle = socket_fd, .address = addressFromPosix(&storage) }; } fn netConnectIpWindows( userdata: ?*anyopaque, address: *const IpAddress, options: IpAddress.ConnectOptions, -) IpAddress.ConnectError!net.Stream { +) IpAddress.ConnectError!net.Socket { if (!have_networking) return error.NetworkDown; if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout"); const t: *Threaded = @ptrCast(@alignCast(userdata)); + _ = t; const family = posixAddressFamily(address); - const socket_handle = try openSocketWsa(t, family, .{ - .mode = options.mode, - .protocol = options.protocol, - }); - errdefer closeSocketWindows(socket_handle); - - var storage: WsaAddress = undefined; - var addr_len = addressToWsa(address, &storage); - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.connect(socket_handle, &storage.any, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable), - .ECONNREFUSED => return syscall.fail(error.ConnectionRefused), - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .ETIMEDOUT => return syscall.fail(error.Timeout), - .EHOSTUNREACH => return syscall.fail(error.HostUnreachable), - .ENETUNREACH => return syscall.fail(error.NetworkUnreachable), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EISCONN => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EWOULDBLOCK => return syscall.fail(error.WouldBlock), - .EACCES => return syscall.fail(error.AccessDenied), - .ENOBUFS => return syscall.fail(error.SystemResources), - .EAFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported), - else => |err| return syscall.unexpectedWsaError(err), - } + const socket_handle = try openSocketAfd(family, .{ .mode = options.mode, .protocol = options.protocol }); + errdefer windows.CloseHandle(socket_handle); + try setSocketOptionAfd(socket_handle, ws2_32.SOL.SOCKET, ws2_32.SO.REUSE_UNICASTPORT, true); + const bound_address = bindSocketIpAfd(socket_handle, &switch (address.*) { + .ip4 => .{ .ip4 = .unspecified(0) }, + .ip6 => .{ .ip6 = .unspecified(0) }, + }, .Active) catch |err| switch (err) { + error.AddressInUse => return error.Unexpected, + else => |e| return e, + }; + const Storage = extern struct { Reserved0: [3]usize = @splat(0), Address: PosixAddress }; + var storage: Storage = .{ .Address = undefined }; + const addr_len = addressToPosix(address, &storage.Address); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.CONNECT, + .in = @as([]const u8, @ptrCast(&storage))[0 .. @offsetOf(Storage, "Address") + addr_len], + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } - - try wsaGetSockName(t, socket_handle, &storage.any, &addr_len); - - return .{ .socket = .{ - .handle = socket_handle, - .address = addressFromWsa(&storage), - } }; -} - -fn netConnectIpUnavailable( - userdata: ?*anyopaque, - address: *const IpAddress, - options: IpAddress.ConnectOptions, -) IpAddress.ConnectError!net.Stream { - _ = userdata; - _ = address; - _ = options; - return error.NetworkDown; + return .{ .handle = socket_handle, .address = bound_address }; } fn netConnectUnixPosix( @@ -12298,6 +12145,7 @@ fn netConnectUnixPosix( const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; const socket_fd = openSocketPosix(posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) { + error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported, error.OptionUnsupported => return error.Unexpected, else => |e| return e, }; @@ -12315,55 +12163,46 @@ fn netConnectUnixWindows( if (!net.has_unix_sockets) return error.AddressFamilyUnsupported; if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); - - const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }); - errdefer closeSocketWindows(socket_handle); - var storage: WsaAddress = undefined; - const addr_len = addressUnixToWsa(address, &storage); - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.connect(socket_handle, &storage.any, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ECONNREFUSED => return syscall.fail(error.FileNotFound), - .EWOULDBLOCK => return syscall.fail(error.WouldBlock), - .EACCES => return syscall.fail(error.AccessDenied), - .ENOBUFS => return syscall.fail(error.SystemResources), - .EAFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EISCONN => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + _ = t; + const is_abstract = address.isAbstract(); + const wps = if (!is_abstract) sliceToPrefixedFileW(null, address.path, .{ + .allow_relative = false, + }) catch |err| switch (err) { + error.NameTooLong, error.BadPathName => return error.FileNotFound, + else => |e| return e, + } else undefined; + const socket_handle = openSocketAfd(ws2_32.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) { + error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported, + else => |e| return e, + }; + errdefer windows.CloseHandle(socket_handle); + if (!is_abstract) try socketOptionAfd(socket_handle, .special, 0, ws2_32.SO.UNIX_PATH, @constCast( + @as([]const u8, @ptrCast(&windows.AFD.SOCKOPT_INFO.UNIX_PATH{ + .Path = wps.data, + }))[0 .. @offsetOf(windows.AFD.SOCKOPT_INFO.UNIX_PATH, "Path") + @sizeOf(windows.WCHAR) * wps.len], + )); + bindSocketUnixAfd(socket_handle, &(net.UnixAddress.init("") catch |err| switch (err) { + error.NameTooLong => unreachable, + })) catch |err| switch (err) { + error.AddressInUse => return error.Unexpected, + else => |e| return e, + }; + const Storage = extern struct { Reserved0: [3]usize = @splat(0), Address: UnixAddress }; + var storage: Storage = .{ .Address = undefined }; + const addr_len = addressUnixToPosix(address, &storage.Address); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.CONNECT, + .in = @as([]const u8, @ptrCast(&storage))[0 .. @offsetOf(Storage, "Address") + addr_len], + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } - return socket_handle; } -fn netConnectUnixUnavailable( - userdata: ?*anyopaque, - address: *const net.UnixAddress, -) net.UnixAddress.ConnectError!net.Socket.Handle { - _ = userdata; - _ = address; - return error.AddressFamilyUnsupported; -} - fn netBindIpPosix( userdata: ?*anyopaque, address: *const IpAddress, @@ -12379,10 +12218,7 @@ fn netBindIpPosix( var addr_len = addressToPosix(address, &storage); try posixBind(socket_fd, &storage.any, addr_len); try posixGetSockName(socket_fd, &storage.any, &addr_len); - return .{ - .handle = socket_fd, - .address = addressFromPosix(&storage), - }; + return .{ .handle = socket_fd, .address = addressFromPosix(&storage) }; } fn netBindIpWindows( @@ -12392,62 +12228,12 @@ fn netBindIpWindows( ) IpAddress.BindError!net.Socket { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); + _ = t; const family = posixAddressFamily(address); - const socket_handle = try openSocketWsa(t, family, .{ - .mode = options.mode, - .protocol = options.protocol, - }); - errdefer closeSocketWindows(socket_handle); - - var storage: WsaAddress = undefined; - var addr_len = addressToWsa(address, &storage); - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.bind(socket_handle, &storage.any, addr_len); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - break; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EADDRINUSE => return syscall.fail(error.AddressInUse), - .EADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .ENOBUFS => return syscall.fail(error.SystemResources), - .ENETDOWN => return syscall.fail(error.NetworkDown), - else => |err| return syscall.unexpectedWsaError(err), - } - } - - try wsaGetSockName(t, socket_handle, &storage.any, &addr_len); - - return .{ - .handle = socket_handle, - .address = addressFromWsa(&storage), - }; -} - -fn netBindIpUnavailable( - userdata: ?*anyopaque, - address: *const IpAddress, - options: IpAddress.BindOptions, -) IpAddress.BindError!net.Socket { - _ = userdata; - _ = address; - _ = options; - return error.NetworkDown; + const socket_handle = try openSocketAfd(family, options); + errdefer windows.CloseHandle(socket_handle); + const bound_address = try bindSocketIpAfd(socket_handle, address, .Active); + return .{ .handle = socket_handle, .address = bound_address }; } fn openSocketPosix( @@ -12465,8 +12251,7 @@ fn openSocketPosix( Unexpected, Canceled, }!posix.socket_t { - const mode = posixSocketMode(options.mode); - const protocol = posixProtocol(options.protocol); + const mode, const protocol = try posixSocketModeProtocol(family, options.mode, options.protocol); const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC; const syscall: Syscall = try .start(); const socket_fd = while (true) { @@ -12498,7 +12283,7 @@ fn openSocketPosix( if (options.ip6_only) { if (posix.IPV6 == void) return error.OptionUnsupported; - try setSocketOption(socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0); + try setSocketOptionPosix(socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0); } return socket_fd; @@ -12530,8 +12315,7 @@ fn netSocketCreatePair( .ip4 => posix.AF.INET, .ip6 => posix.AF.INET6, }; - const mode = posixSocketMode(options.mode); - const protocol = posixProtocol(options.protocol); + const mode, const protocol = try posixSocketModeProtocol(family, options.mode, options.protocol); const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC; var sockets: [2]posix.socket_t = undefined; @@ -12573,56 +12357,102 @@ fn netSocketCreatePair( }; } -fn netSocketCreatePairUnavailable( - userdata: ?*anyopaque, - options: net.Socket.CreatePairOptions, -) net.Socket.CreatePairError![2]net.Socket { - _ = userdata; - _ = options; - return error.OperationUnsupported; +fn openSocketAfd(family: ws2_32.ADDRESS_FAMILY, options: IpAddress.BindOptions) !net.Socket.Handle { + const mode, const protocol = try posixSocketModeProtocol(family, options.mode, options.protocol); + var handle: windows.HANDLE = undefined; + var iosb: windows.IO_STATUS_BLOCK = undefined; + var syscall: Syscall = try .start(); + while (true) switch (windows.ntdll.NtCreateFile( + &handle, + .{ + .STANDARD = .{ .RIGHTS = .{ .WRITE_DAC = true }, .SYNCHRONIZE = true }, + .GENERIC = .{ .WRITE = true, .READ = true }, + }, + &.{ + .ObjectName = @constCast(&windows.UNICODE_STRING.init( + windows.AFD.DEVICE_NAME ++ .{ '\\', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't' }, + )), + }, + &iosb, + null, + .{}, + .{ .READ = true, .WRITE = true }, + .OPEN_IF, + .{ .IO = .ASYNCHRONOUS }, + &windows.AFD.OPEN_PACKET.FULL_EA_INFORMATION{ .Value = .{ + .EndpointType = .{ + .CONNECTIONLESS = switch (options.mode) { + .stream, .seqpacket, .rdm => false, + .dgram, .raw => true, + }, + .MESSAGEMODE = options.mode != .stream, + .RAW = options.mode == .raw, + }, + .GroupID = 0, + .AddressFamily = family, + .SocketType = @bitCast(mode), + .Protocol = @bitCast(protocol), + .TransportDeviceNameLength = 0, + .TransportDeviceName = undefined, + } }, + @sizeOf(windows.AFD.OPEN_PACKET.FULL_EA_INFORMATION), + )) { + .SUCCESS => { + syscall.finish(); + return handle; + }, + .CANCELLED => { + try syscall.checkCancel(); + continue; + }, + .PROTOCOL_NOT_SUPPORTED => return syscall.fail(error.AddressFamilyUnsupported), + .NO_SUCH_FILE => return syscall.fail(error.ProtocolUnsupportedByAddressFamily), + else => |status| return syscall.unexpectedNtstatus(status), + }; } -fn openSocketWsa( - t: *Threaded, - family: posix.sa_family_t, - options: IpAddress.BindOptions, -) !ws2_32.SOCKET { - const mode = posixSocketMode(options.mode); - const protocol = posixProtocol(options.protocol); - // WSA_FLAG_OVERLAPPED is chosen here because without this different - // threads cannot use the same open socket handle. - const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT; - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags); - if (rc != ws2_32.INVALID_SOCKET) { - syscall.finish(); - return rc; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EAFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported), - .EMFILE => return syscall.fail(error.ProcessFdQuotaExceeded), - .ENOBUFS => return syscall.fail(error.SystemResources), - .EPROTONOSUPPORT => return syscall.fail(error.ProtocolUnsupportedByAddressFamily), - else => |err| return syscall.unexpectedWsaError(err), - } +fn bindSocketIpAfd(socket_handle: net.Socket.Handle, address: *const IpAddress, mode: windows.AFD.BIND_INFO.MODE) !IpAddress { + const Storage = extern struct { Info: windows.AFD.BIND_INFO, Address: PosixAddress }; + var storage: Storage = .{ .Info = .{ .Mode = mode }, .Address = undefined }; + const addr_len = addressToPosix(address, &storage.Address); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.BIND, + .in = @as([]const u8, @ptrCast(&storage))[0 .. @offsetOf(Storage, "Address") + addr_len], + .out = @as([]u8, @ptrCast(&storage.Address))[0..addr_len], + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + .SHARING_VIOLATION => return error.AddressInUse, + else => |status| return windows.unexpectedStatus(status), + } + return addressFromPosix(&storage.Address); +} + +fn bindSocketUnixAfd(socket_handle: net.Socket.Handle, address: *const net.UnixAddress) !void { + const Storage = extern struct { Info: windows.AFD.BIND_INFO, Address: UnixAddress }; + var storage: Storage = .{ .Info = .{ .Mode = .Unix }, .Address = undefined }; + const addr_len = addressUnixToPosix(address, &storage.Address); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.BIND, + .in = @as([]const u8, @ptrCast(&storage))[0 .. @offsetOf(Storage, "Address") + addr_len], + .out = @ptrCast(&storage.Address), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + .ADDRESS_ALREADY_EXISTS => return error.AddressInUse, + else => |status| return windows.unexpectedStatus(status), } } -fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream { +fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; + options; var storage: PosixAddress = undefined; var addr_len: posix.socklen_t = @sizeOf(PosixAddress); const syscall: Syscall = try .start(); @@ -12664,55 +12494,71 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve }, } }; - return .{ .socket = .{ - .handle = fd, - .address = addressFromPosix(&storage), - } }; + return .{ .handle = fd, .address = addressFromPosix(&storage) }; } -fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream { +fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); - var storage: WsaAddress = undefined; - var addr_len: i32 = @sizeOf(WsaAddress); - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len); - if (rc != ws2_32.INVALID_SOCKET) { - syscall.finish(); - return .{ .socket = .{ - .handle = rc, - .address = addressFromWsa(&storage), - } }; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ECONNRESET => return syscall.fail(error.ConnectionAborted), - .EMFILE => return syscall.fail(error.ProcessFdQuotaExceeded), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENOBUFS => return syscall.fail(error.SystemResources), - .EFAULT => |err| return syscall.wsaErrorBug(err), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EOPNOTSUPP => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + const Storage = extern struct { + Info: windows.AFD.LISTEN_RESPONSE_INFO, + RemoteAddress: extern union { posix: PosixAddress, unix: UnixAddress }, + }; + var storage: Storage = undefined; + switch ((try deviceIoControl(&.{ + .file = .{ .handle = listen_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.WAIT_FOR_LISTEN, + .out = @ptrCast(&storage), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } + errdefer t.deferAcceptAfd(listen_handle, storage.Info); + const accept_handle = openSocketAfd( + storage.RemoteAddress.posix.any.family, + .{ .mode = options.mode, .protocol = options.protocol }, + ) catch |err| switch (err) { + error.AddressFamilyUnsupported => return error.Unexpected, + error.ProtocolUnsupportedByAddressFamily => return error.Unexpected, + else => |e| return e, + }; + errdefer windows.CloseHandle(accept_handle); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = listen_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.ACCEPT, + .in = @ptrCast(&windows.AFD.ACCEPT_INFO{ + .UseSAN = windows.FALSE, + .Sequence = storage.Info.Sequence, + .AcceptHandle = accept_handle, + }), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), + } + return .{ .handle = accept_handle, .address = addressFromPosix(&storage.RemoteAddress.posix) }; } -fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream { - _ = userdata; - _ = listen_handle; - return error.NetworkDown; +fn deferAcceptAfd(t: *Threaded, listen_handle: net.Socket.Handle, info: windows.AFD.LISTEN_RESPONSE_INFO) void { + const cancel_protection = swapCancelProtection(t, .blocked); + defer _ = swapCancelProtection(t, cancel_protection); + switch ((deviceIoControl(&.{ + .file = .{ .handle = listen_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.DEFER_ACCEPT, + .in = @ptrCast(&windows.AFD.DEFER_ACCEPT_INFO{ + .Sequence = info.Sequence, + .Reject = windows.FALSE, + }), + }) catch |err| switch (err) { + error.Canceled => unreachable, // blocked + }).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + else => |status| windows.unexpectedStatus(status) catch {}, + } } fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { @@ -12798,78 +12644,39 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net. } } -fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { +fn netReadWindows(userdata: ?*anyopaque, socket_handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); + _ = t; - var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined; - const bufs = b: { - var i: usize = 0; - var n: usize = 0; - for (data) |buf| { - if (iovec_buffer.len - i == 0) break; - if (buf.len == 0) continue; - if (std.math.cast(u32, buf.len)) |len| { - iovec_buffer[i] = .{ .buf = buf.ptr, .len = len }; - i += 1; - n += len; - continue; - } - iovec_buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) }; - i += 1; - n += std.math.maxInt(u32); - break; - } - - const bufs = iovec_buffer[0..i]; - assert(bufs[0].len != 0); - - break :b bufs; - }; - - var syscall: AlertableSyscall = try .start(); - while (true) { - var flags: u32 = 0; - var n: u32 = undefined; - const rc = ws2_32.WSARecv(handle, bufs.ptr, @intCast(bufs.len), &n, &flags, null, null); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return n; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .EFAULT => unreachable, // a pointer is not completely contained in user address space. - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EMSGSIZE => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + var iovecs: [max_iovecs_len]windows.AFD.WSABUF(.@"var") = undefined; + var len: u32 = 0; + for (data) |buf| { + if (iovecs.len - len == 0) break; + addAfdBuf(.@"var", &iovecs, &len, buf); } -} -fn netReadUnavailable(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { - _ = userdata; - _ = fd; - _ = data; - return error.NetworkDown; + const iosb = try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.RECEIVE, + .in = @ptrCast(&windows.AFD.RECV_INFO{ + .BufferArray = &iovecs, + .BufferCount = len, + .AfdFlags = .{ .NO_FAST_IO = true, .OVERLAPPED = true }, + .TdiFlags = .{ .NORMAL = true }, + }), + }); + switch (iosb.u.Status) { + .SUCCESS => return iosb.Information, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), + } } fn netSendPosix( userdata: ?*anyopaque, - handle: net.Socket.Handle, + socket_handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: net.SendFlags, ) struct { ?net.Socket.SendError, usize } { @@ -12887,10 +12694,10 @@ fn netSendPosix( var i: usize = 0; while (messages.len - i != 0) { if (have_sendmmsg) { - i += netSendMany(handle, messages[i..], posix_flags) catch |err| return .{ err, i }; + i += netSendManyPosix(socket_handle, messages[i..], posix_flags) catch |err| return .{ err, i }; continue; } - netSendOne(t, handle, &messages[i], posix_flags) catch |err| return .{ err, i }; + t.netSendOnePosix(socket_handle, &messages[i], posix_flags) catch |err| return .{ err, i }; i += 1; } return .{ null, i }; @@ -12898,97 +12705,65 @@ fn netSendPosix( fn netSendWindows( userdata: ?*anyopaque, - handle: net.Socket.Handle, + socket_handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: net.SendFlags, ) struct { ?net.Socket.SendError, usize } { if (!have_networking) return .{ error.NetworkDown, 0 }; const t: *Threaded = @ptrCast(@alignCast(userdata)); - - // Ignored flags: confirm, eor, fastopen - const windows_flags: u32 = - @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) | - @as(u32, if (flags.dont_route) ws2_32.MSG.DONTROUTE else 0); - for (messages, 0..) |*m, i| { - netSendWindowsOne(t, handle, m, windows_flags) catch |err| return .{ err, i }; + t.netSendOneWindows(socket_handle, m, flags) catch |err| return .{ err, i }; } return .{ null, messages.len }; } -fn netSendWindowsOne( +fn netSendOneWindows( t: *Threaded, - handle: net.Socket.Handle, + socket_handle: net.Socket.Handle, message: *net.OutgoingMessage, - flags: u32, + flags: net.SendFlags, ) net.Socket.SendError!void { - var buf: ws2_32.WSABUF = .{ - .buf = @constCast(message.data_ptr), - .len = std.math.cast(u32, message.data_len) orelse return error.MessageOversize, - }; - var n: u32 = undefined; - var address: WsaAddress = undefined; - const address_size = addressToWsa(message.address, &address); - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.WSASendTo( - handle, - (&buf)[0..1], - 1, - &n, - flags, - &address.any, - address_size, - null, - null, - ); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; + _ = t; + _ = flags; + const iovecs: [1]windows.AFD.WSABUF(.@"const") = .{.{ + .buf = message.data_ptr, + .len = std.math.cast(std.os.windows.ULONG, message.data_len) orelse + return error.MessageOversize, + }}; + var storage: PosixAddress = undefined; + const addr_len = addressToPosix(message.address, &storage); + switch ((try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.SEND_DATAGRAM, + .in = @ptrCast(&windows.AFD.SEND_DATAGRAM_INFO{ + .BufferArray = &iovecs, + .BufferCount = iovecs.len, + .AfdFlags = .{ .NO_FAST_IO = true, .OVERLAPPED = true }, + .TdiRequest = undefined, + .TdiConnInfo = .{ + .UserDataLength = undefined, + .UserData = undefined, + .OptionsLength = undefined, + .Options = undefined, + .RemoteAddressLength = @bitCast(addr_len), + .RemoteAddress = &storage, }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .EFAULT => unreachable, // a pointer is not completely contained in user address space. - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EMSGSIZE => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + }), + })).u.Status) { + .SUCCESS => return, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } } -fn netSendUnavailable( - userdata: ?*anyopaque, - handle: net.Socket.Handle, - messages: []net.OutgoingMessage, - flags: net.SendFlags, -) struct { ?net.Socket.SendError, usize } { - _ = userdata; - _ = handle; - _ = messages; - _ = flags; - return .{ error.NetworkDown, 0 }; -} - -fn netSendOne( +fn netSendOnePosix( t: *Threaded, - handle: net.Socket.Handle, + socket_handle: net.Socket.Handle, message: *net.OutgoingMessage, flags: u32, ) net.Socket.SendError!void { + _ = t; var addr: PosixAddress = undefined; var iovec: posix.iovec_const = .{ .base = @constCast(message.data_ptr), .len = message.data_len }; const msg: posix.msghdr_const = .{ @@ -13003,43 +12778,7 @@ fn netSendOne( }; var syscall: if (is_windows) AlertableSyscall else Syscall = try .start(); while (true) { - const rc = posix.system.sendmsg(handle, &msg, flags); - if (is_windows) { - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - message.data_len = @intCast(rc); - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .EACCES => return syscall.fail(error.AccessDenied), - .EADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable), - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .EMSGSIZE => return syscall.fail(error.MessageOversize), - .ENOBUFS => return syscall.fail(error.SystemResources), - .ENOTSOCK => return syscall.fail(error.FileDescriptorNotASocket), - .EAFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported), - .EHOSTUNREACH => return syscall.fail(error.NetworkUnreachable), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENETUNREACH => return syscall.fail(error.NetworkUnreachable), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .EDESTADDRREQ => unreachable, // A destination address is required. - .EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small. - .EINVAL => unreachable, - .ESHUTDOWN => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } - } + const rc = posix.system.sendmsg(socket_handle, &msg, flags); switch (posix.errno(rc)) { .SUCCESS => { syscall.finish(); @@ -13074,8 +12813,8 @@ fn netSendOne( } } -fn netSendMany( - handle: net.Socket.Handle, +fn netSendManyPosix( + socket_handle: net.Socket.Handle, messages: []net.OutgoingMessage, flags: u32, ) net.Socket.SendError!usize { @@ -13106,7 +12845,7 @@ fn netSendMany( const syscall: Syscall = try .start(); while (true) { - const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags); + const rc = posix.system.sendmmsg(socket_handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags); switch (posix.errno(rc)) { .SUCCESS => { syscall.finish(); @@ -13231,11 +12970,12 @@ fn netReceiveWindows( data_buffer: []u8, flags: net.ReceiveFlags, ) struct { ?net.Socket.ReceiveError, usize } { - netReceiveWindowsOne(t, socket_handle, &message_buffer[0], data_buffer, flags) catch |err| return .{ err, 0 }; + t.netReceiveOneWindows(socket_handle, &message_buffer[0], data_buffer, flags) catch |err| + return .{ err, 0 }; return .{ null, 1 }; } -fn netReceiveWindowsOne( +fn netReceiveOneWindows( t: *Threaded, socket_handle: net.Socket.Handle, message: *net.IncomingMessage, @@ -13243,69 +12983,49 @@ fn netReceiveWindowsOne( flags: net.ReceiveFlags, ) net.Socket.ReceiveError!void { if (!have_networking) return error.NetworkDown; - - var windows_flags: u32 = - @as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) | - @as(u32, if (flags.peek) ws2_32.MSG.PEEK else 0) | - @as(u32, if (flags.trunc) ws2_32.MSG.TRUNC else 0); - - var buf: ws2_32.WSABUF = .{ + _ = t; + const iovecs: [1]windows.AFD.WSABUF(.@"var") = .{.{ .buf = data_buffer.ptr, - .len = std.math.cast(u32, data_buffer.len) orelse return error.MessageOversize, - }; - var n: u32 = undefined; - var from_storage: WsaAddress = undefined; - var from_storage_len: i32 = @sizeOf(WsaAddress); - var syscall: AlertableSyscall = try .start(); - - while (true) { - const rc = ws2_32.WSARecvFrom( - socket_handle, - (&buf)[0..1], - 1, - &n, - &windows_flags, - &from_storage.any, - &from_storage_len, - null, - null, - ); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - message.* = .{ - .from = addressFromWsa(&from_storage), - .data = data_buffer[0..n], - .control = &.{}, - .flags = .{ - .eor = false, - .trunc = (windows_flags & ws2_32.MSG.TRUNC) != 0, - .ctrunc = (windows_flags & ws2_32.MSG.CTRUNC) != 0, - .oob = false, - .errqueue = false, + .len = std.math.cast(std.os.windows.ULONG, data_buffer.len) orelse return error.MessageOversize, + }}; + var storage: PosixAddress = undefined; + var addr_len: windows.ULONG = @sizeOf(PosixAddress); + const iosb = try deviceIoControl(&.{ + .file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.RECEIVE_DATAGRAM, + .in = @ptrCast(&windows.AFD.RECV_DATAGRAM_INFO{ + .BufferArray = &iovecs, + .BufferCount = iovecs.len, + .AfdFlags = .{ .NO_FAST_IO = true, .OVERLAPPED = true }, + .TdiFlags = .{ .NORMAL = !flags.oob, .EXPEDITED = flags.oob, .PEEK = flags.peek }, + .Address = &storage, + .AddressLength = &addr_len, + }), + }); + switch (iosb.u.Status) { + .SUCCESS, .RECEIVE_PARTIAL => |status| message.* = .{ + .from = addressFromPosix(&storage), + .data = data_buffer[0..iosb.Information], + .control = &.{}, + .flags = .{ + .eor = false, + .trunc = false, + .ctrunc = false, + .oob = switch (status) { + else => unreachable, + .SUCCESS, .RECEIVE_PARTIAL, .BUFFER_OVERFLOW => false, + .RECEIVE_EXPEDITED, .RECEIVE_PARTIAL_EXPEDITED => true, }, - }; - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; + .errqueue = false, }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .EFAULT => unreachable, // a pointer is not completely contained in user address space. - .EINVAL => |err| return syscall.wsaErrorBug(err), - .EMSGSIZE => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + }, + .RECEIVE_EXPEDITED, + .RECEIVE_PARTIAL_EXPEDITED, + .BUFFER_OVERFLOW, + => |status| return windows.unexpectedStatus(status), // TdiFlags.PARTIAL = false + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } } @@ -13412,17 +13132,17 @@ fn netWriteWindows( ) net.Stream.Writer.Error!usize { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); - comptime assert(is_windows); + _ = t; - var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined; + var iovecs: [max_iovecs_len]windows.AFD.WSABUF(.@"const") = undefined; var len: u32 = 0; - addWsaBuf(&iovecs, &len, header); - for (data[0 .. data.len - 1]) |bytes| addWsaBuf(&iovecs, &len, bytes); + addAfdBuf(.@"const", &iovecs, &len, header); + for (data[0 .. data.len - 1]) |bytes| addAfdBuf(.@"const", &iovecs, &len, bytes); const pattern = data[data.len - 1]; var backup_buffer: [64]u8 = undefined; if (iovecs.len - len != 0) switch (splat) { 0 => {}, - 1 => addWsaBuf(&iovecs, &len, pattern), + 1 => addAfdBuf(.@"const", &iovecs, &len, pattern), else => switch (pattern.len) { 0 => {}, 1 => { @@ -13430,87 +13150,63 @@ fn netWriteWindows( const memset_len = @min(splat_buffer.len, splat); const buf = splat_buffer[0..memset_len]; @memset(buf, pattern[0]); - addWsaBuf(&iovecs, &len, buf); + addAfdBuf(.@"const", &iovecs, &len, buf); var remaining_splat = splat - buf.len; while (remaining_splat > splat_buffer.len and len < iovecs.len) { - addWsaBuf(&iovecs, &len, splat_buffer); + addAfdBuf(.@"const", &iovecs, &len, splat_buffer); remaining_splat -= splat_buffer.len; } - addWsaBuf(&iovecs, &len, splat_buffer[0..@min(remaining_splat, splat_buffer.len)]); + addAfdBuf(.@"const", &iovecs, &len, splat_buffer[0..@min(remaining_splat, splat_buffer.len)]); }, else => for (0..@min(splat, iovecs.len - len)) |_| { - addWsaBuf(&iovecs, &len, pattern); + addAfdBuf(.@"const", &iovecs, &len, pattern); }, }, }; - var syscall: AlertableSyscall = try .start(); - while (true) { - var n: u32 = undefined; - const rc = ws2_32.WSASend(handle, &iovecs, len, &n, 0, null, null); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return n; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - - .ECONNABORTED => return syscall.fail(error.ConnectionResetByPeer), - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .EINVAL => return syscall.fail(error.SocketUnconnected), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENETRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENOBUFS => return syscall.fail(error.SystemResources), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - .EOPNOTSUPP => |err| return syscall.wsaErrorBug(err), - .ESHUTDOWN => |err| return syscall.wsaErrorBug(err), - .IO_PENDING => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + const iosb = try deviceIoControl(&.{ + .file = .{ .handle = handle, .flags = .{ .nonblocking = true } }, + .code = windows.IOCTL.AFD.SEND, + .in = @ptrCast(&windows.AFD.SEND_INFO{ + .BufferArray = &iovecs, + .BufferCount = len, + .AfdFlags = .{ .NO_FAST_IO = true, .OVERLAPPED = true }, + .TdiFlags = .{}, + }), + }); + switch (iosb.u.Status) { + .SUCCESS => return iosb.Information, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } } -fn addWsaBuf(v: []ws2_32.WSABUF, i: *u32, bytes: []const u8) void { +fn addAfdBuf( + comptime mutability: windows.AFD.Mutability, + iovecs: []windows.AFD.WSABUF(mutability), + len: *u32, + bytes: switch (mutability) { + .@"const" => []const u8, + .@"var" => []u8, + }, +) void { + if (bytes.len == 0) return; const cap = std.math.maxInt(u32); var remaining = bytes; while (remaining.len > cap) { - if (v.len - i.* == 0) return; - v[i.*] = .{ .buf = @constCast(remaining.ptr), .len = cap }; - i.* += 1; + if (iovecs.len - len.* == 0) return; + iovecs[len.*] = .{ .buf = remaining.ptr, .len = cap }; + len.* += 1; remaining = remaining[cap..]; } else { @branchHint(.likely); - if (v.len - i.* == 0) return; - v[i.*] = .{ .buf = @constCast(remaining.ptr), .len = @intCast(remaining.len) }; - i.* += 1; + if (iovecs.len - len.* == 0) return; + iovecs[len.*] = .{ .buf = remaining.ptr, .len = @intCast(remaining.len) }; + len.* += 1; } } -fn netWriteUnavailable( - userdata: ?*anyopaque, - handle: net.Socket.Handle, - header: []const u8, - data: []const []const u8, - splat: usize, -) net.Stream.Writer.Error!usize { - _ = userdata; - _ = handle; - _ = header; - _ = data; - _ = splat; - return error.NetworkDown; -} - /// This is either usize or u32. Since, either is fine, let's use the same /// `addBuf` function for both writing to a file and sending network messages. const iovlen_t = switch (native_os) { @@ -13530,16 +13226,10 @@ fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { if (!have_networking) unreachable; const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - switch (native_os) { - .windows => for (handles) |handle| closeSocketWindows(handle), - else => for (handles) |handle| closeFd(handle), - } -} - -fn netCloseUnavailable(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { - _ = userdata; - _ = handles; - unreachable; // How you gonna close something that was impossible to open? + for (handles) |handle| switch (native_os) { + .windows => windows.CloseHandle(handle), + else => closeFd(handle), + }; } fn netShutdownPosix(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { @@ -13577,52 +13267,30 @@ fn netShutdownPosix(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.S fn netShutdownWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void { if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); + _ = t; - const wsa_how: i32 = switch (how) { - .recv => ws2_32.SD_RECEIVE, - .send => ws2_32.SD_SEND, - .both => ws2_32.SD_BOTH, - }; - - var syscall: AlertableSyscall = try .start(); - while (true) { - const rc = ws2_32.shutdown(handle, wsa_how); - if (rc != ws2_32.SOCKET_ERROR) { - syscall.finish(); - return; - } - switch (ws2_32.WSAGetLastError()) { - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => { - try syscall.checkCancel(); - continue; - }, - .NOTINITIALISED => { - syscall.finish(); - try initializeWsa(t); - syscall = try .start(); - continue; - }, - .ECONNABORTED => return syscall.fail(error.ConnectionAborted), - .ECONNRESET => return syscall.fail(error.ConnectionResetByPeer), - .ENETDOWN => return syscall.fail(error.NetworkDown), - .ENOTCONN => return syscall.fail(error.SocketUnconnected), - .EINVAL, .ENOTSOCK => |err| return syscall.wsaErrorBug(err), - else => |err| return syscall.unexpectedWsaError(err), - } + // shutdown does not support apcs at all + switch ((try deviceIoControl(&.{ + .file = .{ .handle = handle, .flags = .{ .nonblocking = false } }, + .code = windows.IOCTL.AFD.PARTIAL_DISCONNECT, + .in = @ptrCast(&windows.AFD.PARTIAL_DISCONNECT_INFO{ + .DisconnectMode = .{ .SEND = how != .recv, .RECEIVE = how != .send }, + .Timeout = -1, + }), + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .INSUFFICIENT_RESOURCES => return error.SystemResources, + else => |status| return windows.unexpectedStatus(status), } } -fn netShutdownUnavailable(_: ?*anyopaque, _: net.Socket.Handle, _: net.ShutdownHow) net.ShutdownError!void { - unreachable; // How you gonna shutdown something that was impossible to open? -} - fn netInterfaceNameResolve( userdata: ?*anyopaque, name: *const net.Interface.Name, ) net.Interface.Name.ResolveError!net.Interface { if (!have_networking) return error.InterfaceNotFound; const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; if (native_os == .linux) { const sock_fd = openSocketPosix(posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) { @@ -13658,8 +13326,66 @@ fn netInterfaceNameResolve( } if (is_windows) { + var ConvertInterfaceNameToLuidW = t.dl.ConvertInterfaceNameToLuidW.load(.acquire); + var ConvertInterfaceLuidToIndex = t.dl.ConvertInterfaceLuidToIndex.load(.acquire); + if (ConvertInterfaceNameToLuidW == null or ConvertInterfaceLuidToIndex == null) { + const iphlpapi_dll = t.dl.iphlpapi_dll.load(.acquire) orelse iphlpapi_dll: { + try Thread.checkCancel(); + var iphlpapi_dll: *anyopaque = undefined; + switch (windows.ntdll.LdrLoadDll(null, null, &.init( + &.{ 'I', 'P', 'H', 'L', 'P', 'A', 'P', 'I', '.', 'D', 'L', 'L' }, + ), &iphlpapi_dll)) { + .SUCCESS => {}, + .DLL_NOT_FOUND => return error.Unexpected, + else => |status| return windows.unexpectedStatus(status), + } + const handle = t.dl.iphlpapi_dll.cmpxchgStrong(null, iphlpapi_dll, .release, .monotonic) orelse + break :iphlpapi_dll iphlpapi_dll; + switch (windows.ntdll.LdrUnloadDll(iphlpapi_dll)) { + .SUCCESS => break :iphlpapi_dll handle.?, + else => |status| return windows.unexpectedStatus(status), + } + }; + switch (windows.ntdll.LdrGetProcedureAddress(iphlpapi_dll, &.init( + &.{ + 'C', 'o', 'n', 'v', 'e', 'r', 't', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', + 'N', 'a', 'm', 'e', 'T', 'o', 'L', 'u', 'i', 'd', 'W', + }, + ), 0, @ptrCast(&ConvertInterfaceNameToLuidW))) { + .SUCCESS => t.dl.ConvertInterfaceNameToLuidW.store(ConvertInterfaceNameToLuidW, .release), + else => |status| return windows.unexpectedStatus(status), + } + switch (windows.ntdll.LdrGetProcedureAddress(iphlpapi_dll, &.init( + &.{ + 'C', 'o', 'n', 'v', 'e', 'r', 't', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', + 'L', 'u', 'i', 'd', 'T', 'o', 'I', 'n', 'd', 'e', 'x', + }, + ), 0, @ptrCast(&ConvertInterfaceLuidToIndex))) { + .SUCCESS => t.dl.ConvertInterfaceLuidToIndex.store(ConvertInterfaceLuidToIndex, .release), + else => |status| return windows.unexpectedStatus(status), + } + } try Thread.checkCancel(); - @panic("TODO implement netInterfaceNameResolve for Windows"); + var name_w: [net.Interface.Name.max_len:0]windows.WCHAR = undefined; + name_w[ + std.unicode.wtf8ToWtf16Le(&name_w, name.toSlice()) catch |err| switch (err) { + error.InvalidWtf8 => return error.InterfaceNotFound, + } + ] = 0; + var luid: windows.NET.LUID = undefined; + switch (ConvertInterfaceNameToLuidW.?(&name_w, &luid)) { + .SUCCESS => {}, + .INVALID_NAME => return error.InterfaceNotFound, + .INVALID_PARAMETER => unreachable, + else => |err| return windows.unexpectedError(err), + } + var index: windows.NET.IFINDEX = undefined; + switch (ConvertInterfaceLuidToIndex.?(&luid, &index)) { + .SUCCESS => {}, + .INVALID_PARAMETER => unreachable, + else => |err| return windows.unexpectedError(err), + } + return .{ .index = @intFromEnum(index) }; } if (builtin.link_libc) { @@ -13672,42 +13398,81 @@ fn netInterfaceNameResolve( @panic("unimplemented"); } -fn netInterfaceNameResolveUnavailable( - userdata: ?*anyopaque, - name: *const net.Interface.Name, -) net.Interface.Name.ResolveError!net.Interface { - _ = userdata; - _ = name; - return error.InterfaceNotFound; -} - fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; - try Thread.checkCancel(); if (native_os == .linux) { - _ = interface; + try Thread.checkCancel(); @panic("TODO implement netInterfaceName for linux"); } if (is_windows) { - @panic("TODO implement netInterfaceName for windows"); + var ConvertInterfaceIndexToLuid = t.dl.ConvertInterfaceIndexToLuid.load(.acquire); + var ConvertInterfaceLuidToNameW = t.dl.ConvertInterfaceLuidToNameW.load(.acquire); + if (ConvertInterfaceIndexToLuid == null or ConvertInterfaceLuidToNameW == null) { + const iphlpapi_dll = t.dl.iphlpapi_dll.load(.acquire) orelse iphlpapi_dll: { + try Thread.checkCancel(); + var iphlpapi_dll: *anyopaque = undefined; + switch (windows.ntdll.LdrLoadDll(null, null, &.init( + &.{ 'I', 'P', 'H', 'L', 'P', 'A', 'P', 'I', '.', 'D', 'L', 'L' }, + ), &iphlpapi_dll)) { + .SUCCESS => {}, + .DLL_NOT_FOUND => return error.Unexpected, + else => |status| return windows.unexpectedStatus(status), + } + const handle = t.dl.iphlpapi_dll.cmpxchgStrong(null, iphlpapi_dll, .release, .monotonic) orelse + break :iphlpapi_dll iphlpapi_dll; + switch (windows.ntdll.LdrUnloadDll(iphlpapi_dll)) { + .SUCCESS => break :iphlpapi_dll handle.?, + else => |status| return windows.unexpectedStatus(status), + } + }; + switch (windows.ntdll.LdrGetProcedureAddress(iphlpapi_dll, &.init( + &.{ + 'C', 'o', 'n', 'v', 'e', 'r', 't', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', + 'I', 'n', 'd', 'e', 'x', 'T', 'o', 'L', 'u', 'i', 'd', + }, + ), 0, @ptrCast(&ConvertInterfaceIndexToLuid))) { + .SUCCESS => t.dl.ConvertInterfaceIndexToLuid.store(ConvertInterfaceIndexToLuid, .release), + else => |status| return windows.unexpectedStatus(status), + } + switch (windows.ntdll.LdrGetProcedureAddress(iphlpapi_dll, &.init( + &.{ + 'C', 'o', 'n', 'v', 'e', 'r', 't', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', + 'L', 'u', 'i', 'd', 'T', 'o', 'N', 'a', 'm', 'e', 'W', + }, + ), 0, @ptrCast(&ConvertInterfaceLuidToNameW))) { + .SUCCESS => t.dl.ConvertInterfaceLuidToNameW.store(ConvertInterfaceLuidToNameW, .release), + else => |status| return windows.unexpectedStatus(status), + } + } + try Thread.checkCancel(); + var luid: windows.NET.LUID = undefined; + switch (ConvertInterfaceIndexToLuid.?(@enumFromInt(interface.index), &luid)) { + .SUCCESS => {}, + .FILE_NOT_FOUND => return error.InterfaceNotFound, + .INVALID_PARAMETER => unreachable, + else => |err| return windows.unexpectedError(err), + } + var name_w: [net.Interface.Name.max_len:0]windows.WCHAR = undefined; + switch (ConvertInterfaceLuidToNameW.?(&luid, &name_w, name_w.len)) { + .SUCCESS => {}, + .INVALID_PARAMETER => unreachable, + .NOT_ENOUGH_MEMORY => return error.NameTooLong, + else => |err| return windows.unexpectedError(err), + } + var name: [3 * net.Interface.Name.max_len]u8 = undefined; + return .fromSlice(name[0..std.unicode.wtf16LeToWtf8(&name, std.mem.sliceTo(&name_w, 0))]); } if (builtin.link_libc) { + try Thread.checkCancel(); @panic("TODO implement netInterfaceName for libc"); } @panic("unimplemented"); } -fn netInterfaceNameUnavailable(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { - _ = userdata; - _ = interface; - return error.Unexpected; -} - fn netLookup( userdata: ?*anyopaque, host_name: HostName, @@ -13716,25 +13481,12 @@ fn netLookup( ) net.HostName.LookupError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); defer resolved.close(io(t)); - netLookupFallible(t, host_name, resolved, options) catch |err| switch (err) { + t.netLookupFallible(host_name, resolved, options) catch |err| switch (err) { error.Closed => unreachable, // `resolved` must not be closed until `netLookup` returns else => |e| return e, }; } -fn netLookupUnavailable( - userdata: ?*anyopaque, - host_name: HostName, - resolved: *Io.Queue(HostName.LookupResult), - options: HostName.LookupOptions, -) net.HostName.LookupError!void { - _ = host_name; - _ = options; - const t: *Threaded = @ptrCast(@alignCast(userdata)); - resolved.close(io(t)); - return error.NetworkDown; -} - fn netLookupFallible( t: *Threaded, host_name: HostName, @@ -13743,88 +13495,128 @@ fn netLookupFallible( ) (net.HostName.LookupError || Io.QueueClosedError)!void { if (!have_networking) return error.NetworkDown; - const t_io = io(t); + const t_io = t.io(); const name = host_name.bytes; assert(name.len <= HostName.max_len); if (is_windows) { - var name_buffer: [HostName.max_len + 1]u16 = undefined; - const name_len = std.unicode.wtf8ToWtf16Le(&name_buffer, host_name.bytes) catch - unreachable; // HostName is prevalidated. - name_buffer[name_len] = 0; - const name_w = name_buffer[0..name_len :0]; - - var port_buffer: [8]u8 = undefined; - var port_buffer_wide: [8]u16 = undefined; - const port = std.fmt.bufPrint(&port_buffer, "{d}", .{options.port}) catch - unreachable; // `port_buffer` is big enough for decimal u16. - for (port, port_buffer_wide[0..port.len]) |byte, *wide| - wide.* = std.mem.nativeToLittle(u16, byte); - port_buffer_wide[port.len] = 0; - const port_w = port_buffer_wide[0..port.len :0]; - - const hints: ws2_32.ADDRINFOEXW = .{ - .flags = .{ .NUMERICSERV = true }, - .family = if (options.family) |f| switch (f) { - .ip4 => posix.AF.INET, - .ip6 => posix.AF.INET6, - } else posix.AF.UNSPEC, - .socktype = posix.SOCK.STREAM, - .protocol = posix.IPPROTO.TCP, - .canonname = null, - .addr = null, - .addrlen = 0, - .blob = null, - .bloblen = 0, - .provider = null, - .next = null, - }; - var res: *ws2_32.ADDRINFOEXW = undefined; - const timeout: ?*ws2_32.timeval = null; - while (true) { - // TODO: hook this up to cancelation with `NtDelayExecution` and APC callbacks. - try Thread.checkCancel(); - // TODO make this append to the queue eagerly rather than blocking until the whole thing finishes - const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, null)); - switch (rc) { - @as(ws2_32.WinsockError, @enumFromInt(0)) => break, - .EINTR, .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => continue, - .NOTINITIALISED => { - try initializeWsa(t); - continue; - }, - .TRY_AGAIN => return error.NameServerFailure, - .NO_RECOVERY => return error.NameServerFailure, - .EAFNOSUPPORT => return error.AddressFamilyUnsupported, - .NOT_ENOUGH_MEMORY => return error.SystemResources, - .HOST_NOT_FOUND => return error.UnknownHostName, - .TYPE_NOT_FOUND => return error.ProtocolUnsupportedByAddressFamily, - .ESOCKTNOSUPPORT => return error.ProtocolUnsupportedBySystem, - .EINVAL => |err| return windows.wsaErrorBug(err), - else => |err| return windows.unexpectedWsaError(err), - } + if (options.family == null) { + if (IpAddress.parseIp4(name, options.port)) |addr| { + try resolved.putAll(t_io, &.{ + .{ .address = addr }, + .{ .canonical_name = copyCanon(options.canonical_name_buffer, name) }, + }); + return; + } else |_| {} } - defer ws2_32.FreeAddrInfoExW(res); - var it: ?*ws2_32.ADDRINFOEXW = res; - var canon_name: ?[*:0]const u16 = null; - while (it) |info| : (it = info.next) { - const addr = info.addr orelse continue; - try resolved.putOne(t_io, .{ .address = addressFromWsa(@alignCast(@fieldParentPtr("any", addr))) }); - - if (info.canonname) |n| { - if (canon_name == null) { - canon_name = n; + var DnsQueryEx = t.dl.DnsQueryEx.load(.acquire); + //var DnsCancelQuery = t.dl.DnsCancelQuery.load(.acquire); + var DnsFree = t.dl.DnsFree.load(.acquire); + if (DnsQueryEx == null or + //DnsCancelQuery == null or + DnsFree == null) + { + const dnsapi_dll = t.dl.dnsapi_dll.load(.acquire) orelse dnsapi_dll: { + try Thread.checkCancel(); + var dnsapi_dll: *anyopaque = undefined; + switch (windows.ntdll.LdrLoadDll(null, null, &.init( + &.{ 'd', 'n', 's', 'a', 'p', 'i', '.', 'd', 'l', 'l' }, + ), &dnsapi_dll)) { + .SUCCESS => {}, + .DLL_NOT_FOUND => return error.Unexpected, + else => |status| return windows.unexpectedStatus(status), } + const handle = t.dl.dnsapi_dll.cmpxchgStrong(null, dnsapi_dll, .release, .monotonic) orelse + break :dnsapi_dll dnsapi_dll; + switch (windows.ntdll.LdrUnloadDll(dnsapi_dll)) { + .SUCCESS => break :dnsapi_dll handle.?, + else => |status| return windows.unexpectedStatus(status), + } + }; + switch (windows.ntdll.LdrGetProcedureAddress(dnsapi_dll, &.init( + &.{ 'D', 'n', 's', 'Q', 'u', 'e', 'r', 'y', 'E', 'x' }, + ), 0, @ptrCast(&DnsQueryEx))) { + .SUCCESS => t.dl.DnsQueryEx.store(DnsQueryEx, .release), + else => |status| return windows.unexpectedStatus(status), + } + //switch (windows.ntdll.LdrGetProcedureAddress(dnsapi_dll, &.init( + // &.{ 'D', 'n', 's', 'C', 'a', 'n', 'c', 'e', 'l', 'Q', 'u', 'e', 'r', 'y' }, + //), 0, @ptrCast(&DnsCancelQuery))) { + // .SUCCESS => t.dl.DnsCancelQuery.store(DnsCancelQuery, .release), + // else => |status| return windows.unexpectedStatus(status), + //} + switch (windows.ntdll.LdrGetProcedureAddress(dnsapi_dll, &.init( + &.{ 'D', 'n', 's', 'F', 'r', 'e', 'e' }, + ), 0, @ptrCast(&DnsFree))) { + .SUCCESS => t.dl.DnsFree.store(DnsFree, .release), + else => |status| return windows.unexpectedStatus(status), } } - if (canon_name) |n| { - const len = std.unicode.wtf16LeToWtf8(options.canonical_name_buffer, std.mem.sliceTo(n, 0)); - try resolved.putOne(t_io, .{ .canonical_name = .{ - .bytes = options.canonical_name_buffer[0..len], - } }); + const current_thread = Thread.current; + var lookup_dns: LookupDnsWindows = .{ + .threaded = t, + .thread = if (current_thread) |thread| thread.handle else undefined, + .resolved = resolved, + .options = options, + .results = .{ + .Version = 1, + .QueryStatus = undefined, + .QueryOptions = undefined, + .pQueryRecords = undefined, + .Reserved = undefined, + }, + .done = false, + }; + var host_name_w: [HostName.max_len:0]windows.WCHAR = undefined; + host_name_w[ + std.unicode.wtf8ToWtf16Le(&host_name_w, name) catch |err| switch (err) { + error.InvalidWtf8 => return error.UnknownHostName, + } + ] = 0; + //var cancel_token: windows.DNS.QUERY.CANCEL = undefined; + switch (DnsQueryEx.?(&.{ + .Version = 1, + .QueryName = &host_name_w, + .QueryType = if (options.family == .ip4) .A else .AAAA, + .QueryOptions = .{ + .ADDRCONFIG = true, + .DUAL_ADDR = options.family == null, + .MULTICAST_WAIT = true, + }, + .pQueryCompletionCallback = if (current_thread) |_| &LookupDnsWindows.completed else null, + }, &lookup_dns.results, + //&cancel_token, + null)) { + // We must wait for the APC routine. + .SUCCESS, .REQUEST_PENDING => |status| if (current_thread) |_| { + while (!@atomicLoad(bool, &lookup_dns.done, .acquire)) { + // Once we get here we must not return from the function until the + // operation completes, thereby releasing references to `host_name_w`, + // `lookup_dns.results`, and `cancel_token`. + const alertable_syscall = AlertableSyscall.start() catch |err| switch (err) { + error.Canceled => |e| { + //_ = DnsCancelQuery.?(&cancel_token); + while (!@atomicLoad(bool, &lookup_dns.done, .acquire)) waitForApcOrAlert(); + return e; + }, + }; + waitForApcOrAlert(); + alertable_syscall.finish(); + } + } else switch (status) { + .SUCCESS => try lookup_dns.completedFallible(), + .REQUEST_PENDING => unreachable, // `pQueryCompletionCallback` was `null` + else => unreachable, + }, + else => |status| lookup_dns.results.QueryStatus = status, + } + switch (lookup_dns.results.QueryStatus) { + .SUCCESS => return, + .REQUEST_PENDING => unreachable, // already handled + .INVALID_NAME, .NO_RECORDS => return error.UnknownHostName, + else => |status| return windows.unexpectedError(@enumFromInt(@intFromEnum(status))), } - return; } // On Linux, glibc provides getaddrinfo_a which is capable of supporting our semantics. @@ -13855,7 +13647,7 @@ fn netLookupFallible( } else |_| {} } - lookupHosts(t, host_name, resolved, options) catch |err| switch (err) { + t.lookupHosts(host_name, resolved, options) catch |err| switch (err) { error.UnknownHostName => {}, else => |e| return e, }; @@ -13890,7 +13682,7 @@ fn netLookupFallible( return; } - return lookupDnsSearch(t, host_name, resolved, options); + return t.lookupDnsSearch(host_name, resolved, options); } if (native_os == .openbsd) { @@ -13908,16 +13700,16 @@ fn netLookupFallible( if (builtin.link_libc) { // This operating system lacks a way to resolve asynchronously. We are // stuck with getaddrinfo. - var name_buffer: [HostName.max_len + 1]u8 = undefined; - @memcpy(name_buffer[0..host_name.bytes.len], host_name.bytes); - name_buffer[host_name.bytes.len] = 0; - const name_c = name_buffer[0..host_name.bytes.len :0]; + var name_buffer: [HostName.max_len:0]u8 = undefined; + @memcpy(name_buffer[0..name.len], name); + name_buffer[name.len] = 0; + const name_c = name_buffer[0..name.len :0]; var port_buffer: [8]u8 = undefined; const port_c = std.fmt.bufPrintZ(&port_buffer, "{d}", .{options.port}) catch unreachable; const hints: posix.addrinfo = .{ - .flags = .{ .NUMERICSERV = true }, + .flags = .{ .CANONNAME = options.request_canonical_name, .NUMERICSERV = true }, .family = posix.AF.UNSPEC, .socktype = posix.SOCK.STREAM, .protocol = posix.IPPROTO.TCP, @@ -14168,13 +13960,6 @@ const UnixAddress = extern union { un: posix.sockaddr.un, }; -const WsaAddress = extern union { - any: ws2_32.sockaddr, - in: ws2_32.sockaddr.in, - in6: ws2_32.sockaddr.in6, - un: ws2_32.sockaddr.un, -}; - pub fn posixAddressFamily(a: *const IpAddress) posix.sa_family_t { return switch (a.*) { .ip4 => posix.AF.INET, @@ -14190,14 +13975,6 @@ pub fn addressFromPosix(posix_address: *const PosixAddress) IpAddress { }; } -fn addressFromWsa(wsa_address: *const WsaAddress) IpAddress { - return switch (wsa_address.any.family) { - posix.AF.INET => .{ .ip4 = address4FromWsa(&wsa_address.in) }, - posix.AF.INET6 => .{ .ip6 = address6FromWsa(&wsa_address.in6) }, - else => .{ .ip4 = .loopback(0) }, - }; -} - pub fn addressToPosix(a: *const IpAddress, storage: *PosixAddress) posix.socklen_t { return switch (a.*) { .ip4 => |ip4| { @@ -14211,31 +13988,27 @@ pub fn addressToPosix(a: *const IpAddress, storage: *PosixAddress) posix.socklen }; } -fn addressToWsa(a: *const IpAddress, storage: *WsaAddress) i32 { - return switch (a.*) { - .ip4 => |ip4| { - storage.in = address4ToPosix(ip4); - return @sizeOf(posix.sockaddr.in); - }, - .ip6 => |*ip6| { - storage.in6 = address6ToPosix(ip6); - return @sizeOf(posix.sockaddr.in6); - }, - }; -} - fn addressUnixToPosix(a: *const net.UnixAddress, storage: *UnixAddress) posix.socklen_t { - @memcpy(storage.un.path[0..a.path.len], a.path); storage.un.family = posix.AF.UNIX; - storage.un.path[a.path.len] = 0; - return @sizeOf(posix.sockaddr.un); -} - -fn addressUnixToWsa(a: *const net.UnixAddress, storage: *WsaAddress) i32 { - @memcpy(storage.un.path[0..a.path.len], a.path); - storage.un.family = posix.AF.UNIX; - storage.un.path[a.path.len] = 0; - return @sizeOf(posix.sockaddr.un); + var path_len = switch (native_os) { + .windows => @min(a.path.len, storage.un.path.len), + else => a.path.len, + }; + // With the AFD API, `sockaddr.un` is purely informational, so + // use a suffix which is usually the most relevant part of a path. + @memcpy(storage.un.path[0..path_len], a.path[a.path.len - path_len ..]); + if (storage.un.path.len - path_len > 0) { + @branchHint(.likely); + storage.un.path[path_len] = 0; + path_len += 1; + } + switch (native_os) { + .windows => { + if (storage.un.path[0] == 0) @memset(storage.un.path[path_len..], 0); + return @sizeOf(posix.sockaddr.un); + }, + else => return @intCast(@offsetOf(posix.sockaddr.un, "path") + path_len), + } } fn address4FromPosix(in: *const posix.sockaddr.in) net.Ip4Address { @@ -14254,22 +14027,6 @@ fn address6FromPosix(in6: *const posix.sockaddr.in6) net.Ip6Address { }; } -fn address4FromWsa(in: *const ws2_32.sockaddr.in) net.Ip4Address { - return .{ - .port = std.mem.bigToNative(u16, in.port), - .bytes = @bitCast(in.addr), - }; -} - -fn address6FromWsa(in6: *const ws2_32.sockaddr.in6) net.Ip6Address { - return .{ - .port = std.mem.bigToNative(u16, in6.port), - .bytes = in6.addr, - .flow = in6.flowinfo, - .interface = .{ .index = in6.scope_id }, - }; -} - fn address4ToPosix(a: net.Ip4Address) posix.sockaddr.in { return .{ .port = std.mem.nativeToBig(u16, a.port), @@ -14291,20 +14048,30 @@ pub fn errnoBug(err: posix.E) Io.UnexpectedError { return error.Unexpected; } -pub fn posixSocketMode(mode: net.Socket.Mode) u32 { - return switch (mode) { - .stream => posix.SOCK.STREAM, - .dgram => posix.SOCK.DGRAM, - .seqpacket => posix.SOCK.SEQPACKET, - .raw => posix.SOCK.RAW, - .rdm => posix.SOCK.RDM, +pub fn posixSocketModeProtocol(family: posix.sa_family_t, mode: net.Socket.Mode, protocol: ?net.Protocol) !struct { u32, u32 } { + return .{ + switch (mode) { + .stream => posix.SOCK.STREAM, + .dgram => posix.SOCK.DGRAM, + .seqpacket => posix.SOCK.SEQPACKET, + .raw => posix.SOCK.RAW, + .rdm => posix.SOCK.RDM, + }, + if (protocol) |p| @intFromEnum(p) else if (is_windows) switch (family) { + posix.AF.UNIX => switch (mode) { + .stream => 0, + else => return error.ProtocolUnsupportedByAddressFamily, + }, + posix.AF.INET, posix.AF.INET6 => @intFromEnum(@as(net.Protocol, switch (mode) { + .stream => .tcp, + .dgram => .udp, + else => return error.ProtocolUnsupportedByAddressFamily, + })), + else => return error.ProtocolUnsupportedByAddressFamily, + } else 0, }; } -pub fn posixProtocol(protocol: ?net.Protocol) u32 { - return @intFromEnum(protocol orelse return 0); -} - pub fn recoverableOsBugDetected() void { if (is_debug) unreachable; } @@ -14528,7 +14295,7 @@ fn lookupDnsSearch( while (it.next()) |token| { @memcpy(options.canonical_name_buffer[canon_name.len + 1 ..][0..token.len], token); const lookup_canon_name = options.canonical_name_buffer[0 .. canon_name.len + 1 + token.len]; - if (lookupDns(t, lookup_canon_name, &rc, resolved, options)) |result| { + if (t.lookupDns(lookup_canon_name, &rc, resolved, options)) |result| { return result; } else |err| switch (err) { error.UnknownHostName, error.NoAddressReturned => continue, @@ -14537,7 +14304,7 @@ fn lookupDnsSearch( } const lookup_canon_name = options.canonical_name_buffer[0..canon_name.len]; - return lookupDns(t, lookup_canon_name, &rc, resolved, options); + return t.lookupDns(lookup_canon_name, &rc, resolved, options); } fn lookupDns( @@ -14610,7 +14377,7 @@ fn lookupDns( send: while (now_ts.nanoseconds < final_ts.nanoseconds) : (now_ts = clock.now(t_io)) { const max_messages = queries_buffer.len * HostName.ResolvConf.max_nameservers; { - var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined; + var message_buffer: [max_messages]net.OutgoingMessage = undefined; var message_i: usize = 0; for (queries, answers) |query, *answer| { if (answer.len != 0) continue; @@ -14632,7 +14399,7 @@ fn lookupDns( } }; while (true) { - var message_buffer: [max_messages]Io.net.IncomingMessage = @splat(.init); + var message_buffer: [max_messages]net.IncomingMessage = @splat(.init); const buf = answer_buffer[answer_buffer_i..]; const recv_err, const recv_n = socket.receiveManyTimeout(t_io, &message_buffer, buf, .{}, timeout); for (message_buffer[0..recv_n]) |*received_message| { @@ -14666,7 +14433,7 @@ fn lookupDns( if (answers_remaining == 0) break :send; }, 2 => { - var retry_message: Io.net.OutgoingMessage = .{ + var retry_message: net.OutgoingMessage = .{ .address = ns, .data_ptr = query.ptr, .data_len = query.len, @@ -14753,7 +14520,7 @@ fn lookupHosts( var line_buf: [512]u8 = undefined; var file_reader = file.reader(t_io, &line_buf); - return lookupHostsReader(t, host_name, resolved, options, &file_reader.interface) catch |err| switch (err) { + return t.lookupHostsReader(host_name, resolved, options, &file_reader.interface) catch |err| switch (err) { error.ReadFailed => switch (file_reader.err.?) { error.Canceled => |e| return e, else => { @@ -14863,6 +14630,58 @@ fn writeResolutionQuery(q: *[280]u8, op: u4, dname: []const u8, class: u8, ty: H return n; } +const LookupDnsWindows = struct { + threaded: *Threaded, + thread: Thread.Handle, + resolved: *Io.Queue(HostName.LookupResult), + options: HostName.LookupOptions, + results: windows.DNS.QUERY.RESULT, + done: bool, + + fn completed( + pQueryContext: ?*anyopaque, + pQueryResults: *windows.DNS.QUERY.RESULT, + ) callconv(.winapi) void { + _ = pQueryContext; + const lookup_dns: *LookupDnsWindows = @fieldParentPtr("results", pQueryResults); + lookup_dns.completedFallible() catch |err| switch (err) { + error.Closed => unreachable, // `resolved` must not be closed until `netLookup` returns + error.Canceled => unreachable, // called from an uncancelable thread + }; + @atomicStore(bool, &lookup_dns.done, true, .release); + _ = windows.ntdll.NtAlertThread(lookup_dns.thread); + } + fn completedFallible(lookup_dns: *LookupDnsWindows) (Io.QueueClosedError || Io.Cancelable)!void { + assert(!lookup_dns.done); + const t = lookup_dns.threaded; + defer t.dl.DnsFree.raw.?(lookup_dns.results.pQueryRecords, .RecordList); + if (lookup_dns.results.QueryStatus != .SUCCESS) return; + const t_io = t.io(); + var record_it = lookup_dns.results.pQueryRecords; + while (record_it) |record| : (record_it = record.pNext) switch (record.wType) { + else => {}, + .A => try lookup_dns.resolved.putOne(t_io, .{ + .address = .{ .ip4 = .{ .bytes = record.Data.A, .port = lookup_dns.options.port } }, + }), + .AAAA => { + const ip6: net.Ip6Address = .{ + .bytes = record.Data.AAAA, + .port = lookup_dns.options.port, + }; + try lookup_dns.resolved.putOne(t_io, .{ + .address = if (lookup_dns.options.family) |_| .{ .ip6 = ip6 } else .fromIp6(ip6), + }); + }, + }; + if (lookup_dns.results.pQueryRecords) |record| try lookup_dns.resolved.putOne(t_io, .{ + .canonical_name = .{ .bytes = lookup_dns.options.canonical_name_buffer[0..std.unicode.wtf16LeToWtf8( + lookup_dns.options.canonical_name_buffer, + std.mem.span(@as([*:0]const windows.WCHAR, @ptrCast(@alignCast(record.pName)))), + )] }, + }); + } +}; + fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) HostName { const dest = canonical_name_buffer[0..name.len]; @memcpy(dest, name); @@ -14879,64 +14698,6 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos /// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention) const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11; -fn closeSocketWindows(s: ws2_32.SOCKET) void { - const rc = ws2_32.closesocket(s); - if (is_debug) switch (rc) { - 0 => {}, - ws2_32.SOCKET_ERROR => switch (ws2_32.WSAGetLastError()) { - else => recoverableOsBugDetected(), - }, - else => recoverableOsBugDetected(), - }; -} - -const Wsa = struct { - status: Status = .uninitialized, - mutex: Io.Mutex = .init, - init_error: ?Wsa.InitError = null, - - const Status = enum { uninitialized, initialized, failure }; - - const InitError = error{ - ProcessFdQuotaExceeded, - NetworkDown, - VersionUnsupported, - BlockingOperationInProgress, - } || Io.UnexpectedError; -}; - -fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void { - const wsa = &t.wsa; - mutexLock(&wsa.mutex); - defer mutexUnlock(&wsa.mutex); - switch (wsa.status) { - .uninitialized => { - var wsa_data: ws2_32.WSADATA = undefined; - const minor_version = 2; - const major_version = 2; - switch (ws2_32.WSAStartup((@as(windows.WORD, minor_version) << 8) | major_version, &wsa_data)) { - 0 => { - wsa.status = .initialized; - return; - }, - else => |err_int| { - wsa.status = .failure; - wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) { - .SYSNOTREADY => error.NetworkDown, - .VERNOTSUPPORTED => error.VersionUnsupported, - .EINPROGRESS => error.BlockingOperationInProgress, - .EPROCLIM => error.ProcessFdQuotaExceeded, - else => |err| windows.unexpectedWsaError(err), - }; - }, - } - }, - .initialized => return, - .failure => {}, - } - return error.NetworkDown; -} - fn doNothingSignalHandler(_: posix.SIG) callconv(.c) void {} const WindowsEnvironStrings = struct { @@ -16196,7 +15957,7 @@ fn windowsCreateProcessPathExt( try dir_buf.append(arena, 0); defer dir_buf.shrinkRetainingCapacity(dir_path_len); const dir_path_z = dir_buf.items[0 .. dir_buf.items.len - 1 :0]; - const prefixed_path = try wToPrefixedFileW(null, dir_path_z); + const prefixed_path = try wToPrefixedFileW(null, dir_path_z, .{}); break :dir dirOpenDirWindows(.cwd(), prefixed_path.span(), .{ .iterate = true, }) catch |err| switch (err) { diff --git a/lib/std/Io/Threaded/test.zig b/lib/std/Io/Threaded/test.zig index fff802b191..ab9dd03da1 100644 --- a/lib/std/Io/Threaded/test.zig +++ b/lib/std/Io/Threaded/test.zig @@ -282,7 +282,7 @@ test "memory mapping fallback" { /// Wrapper around RtlDosPathNameToNtPathName_U for use in comparing /// the behavior of RtlDosPathNameToNtPathName_U with wToPrefixedFileW /// Note: RtlDosPathNameToNtPathName_U is not used in the Zig implementation -// because it allocates. +/// because it allocates. fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpace { var out: windows.UNICODE_STRING = undefined; const rc = windows.ntdll.RtlDosPathNameToNtPathName_U(path, &out, null, null); @@ -303,7 +303,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpa fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path: []const u8) !void { const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path); const expected_path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(expected_path); - const actual_path = try Io.Threaded.wToPrefixedFileW(null, path_utf16); + const actual_path = try Io.Threaded.wToPrefixedFileW(null, path_utf16, .{}); std.testing.expectEqualSlices(u16, expected_path_utf16, actual_path.span()) catch |e| { std.debug.print("got '{f}', expected '{f}'\n", .{ std.unicode.fmtUtf16Le(actual_path.span()), std.unicode.fmtUtf16Le(expected_path_utf16) }); return e; @@ -320,7 +320,7 @@ fn testToPrefixedFileWithOracle(comptime path: []const u8, comptime expected_pat /// Test that the Zig conversion matches the conversion that RtlDosPathNameToNtPathName_U does. fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void { const path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(path); - const zig_result = try Io.Threaded.wToPrefixedFileW(null, path_utf16); + const zig_result = try Io.Threaded.wToPrefixedFileW(null, path_utf16, .{}); const win32_api_result = try RtlDosPathNameToNtPathName_U(path_utf16); std.testing.expectEqualSlices(u16, win32_api_result.span(), zig_result.span()) catch |e| { std.debug.print("got '{f}', expected '{f}'\n", .{ std.unicode.fmtUtf16Le(zig_result.span()), std.unicode.fmtUtf16Le(win32_api_result.span()) }); diff --git a/lib/std/Io/Uring.zig b/lib/std/Io/Uring.zig index 9597638e1e..69a8a28aae 100644 --- a/lib/std/Io/Uring.zig +++ b/lib/std/Io/Uring.zig @@ -32,8 +32,7 @@ const pathToPosix = Io.Threaded.pathToPosix; const pid_t = linux.pid_t; const PosixAddress = Io.Threaded.PosixAddress; const posixAddressFamily = Io.Threaded.posixAddressFamily; -const posixProtocol = Io.Threaded.posixProtocol; -const posixSocketMode = Io.Threaded.posixSocketMode; +const posixSocketModeProtocol = Io.Threaded.posixSocketModeProtocol; const process = std.process; const recoverableOsBugDetected = Io.Threaded.recoverableOsBugDetected; const setTimestampToPosix = Io.Threaded.setTimestampToPosix; @@ -4952,9 +4951,9 @@ fn randomSecure(userdata: ?*anyopaque, buffer: []u8) Io.RandomSecureError!void { fn netListenIpUnavailable( userdata: ?*anyopaque, - address: net.IpAddress, + address: *const net.IpAddress, options: net.IpAddress.ListenOptions, -) net.IpAddress.ListenError!net.Server { +) net.IpAddress.ListenError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = address; @@ -4965,10 +4964,12 @@ fn netListenIpUnavailable( fn netAcceptUnavailable( userdata: ?*anyopaque, listen_handle: net.Socket.Handle, -) net.Server.AcceptError!net.Stream { + options: net.Server.AcceptOptions, +) net.Server.AcceptError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = listen_handle; + _ = options; return error.NetworkDown; } @@ -4987,17 +4988,14 @@ fn netBindIp( var addr_len = addressToPosix(address, &storage); try ev.bind(&maybe_sync.cancel_region, socket_fd, &storage.any, addr_len); try ev.getsockname(try maybe_sync.enterSync(ev), socket_fd, &storage.any, &addr_len); - return .{ - .handle = socket_fd, - .address = addressFromPosix(&storage), - }; + return .{ .handle = socket_fd, .address = addressFromPosix(&storage) }; } fn netConnectIpUnavailable( userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions, -) net.IpAddress.ConnectError!net.Stream { +) net.IpAddress.ConnectError!net.Socket { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; _ = address; @@ -5941,8 +5939,7 @@ fn socket( Unexpected, Canceled, }!fd_t { - const mode = posixSocketMode(options.mode); - const protocol = posixProtocol(options.protocol); + const mode, const protocol = try posixSocketModeProtocol(family, options.mode, options.protocol); const socket_fd = while (true) { const thread = try cancel_region.awaitIoUring(); thread.enqueue().* = .{ diff --git a/lib/std/Io/net.zig b/lib/std/Io/net.zig index 6d5b11e1b1..079d9fa5f4 100644 --- a/lib/std/Io/net.zig +++ b/lib/std/Io/net.zig @@ -41,6 +41,7 @@ pub const Protocol = enum(u32) { ethernet = 143, raw = 255, mptcp = 262, + _, }; /// Windows 10 added support for unix sockets in build 17063, redstone 4 is the @@ -159,6 +160,11 @@ pub const IpAddress = union(enum) { } } + /// Converts from an IPv4-mapped IPv6 address, or returns the IPv6 address directly. + pub fn fromIp6(ip6: Ip6Address) IpAddress { + return if (Ip4Address.fromIp6(ip6)) |ip4| .{ .ip4 = ip4 } else .{ .ip6 = ip6 }; + } + /// Includes the optional scope ("%foo" at the end) in IPv6 addresses. /// /// See `format` for an alternative that omits scopes and does @@ -237,8 +243,14 @@ pub const IpAddress = union(enum) { /// Waits for a TCP connection. When using this API, `bind` does not need /// to be called. The returned `Server` has an open `stream`. - pub fn listen(address: IpAddress, io: Io, options: ListenOptions) ListenError!Server { - return io.vtable.netListenIp(io.userdata, address, options); + pub fn listen(address: *const IpAddress, io: Io, options: ListenOptions) ListenError!Server { + return .{ + .socket = try io.vtable.netListenIp(io.userdata, address, options), + .options = if (Server.AcceptOptions != void) .{ + .mode = options.mode, + .protocol = options.protocol, + }, + }; } pub const BindError = error{ @@ -320,8 +332,8 @@ pub const IpAddress = union(enum) { }; /// Initiates a connection-oriented network stream. - pub fn connect(address: IpAddress, io: Io, options: ConnectOptions) ConnectError!Stream { - return io.vtable.netConnectIp(io.userdata, &address, options); + pub fn connect(address: *const IpAddress, io: Io, options: ConnectOptions) ConnectError!Stream { + return .{ .socket = try io.vtable.netConnectIp(io.userdata, address, options) }; } }; @@ -344,6 +356,23 @@ pub const Ip4Address = struct { }; } + /// Converts from an IPv4-mapped IPv6 address, or returns `null`. + pub fn fromIp6(ip6: Ip6Address) ?Ip4Address { + return if (std.mem.eql(u8, ip6.bytes[0..12], &.{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) .{ + .bytes = ip6.bytes[12..].*, + .port = ip6.port, + } else null; + } + + /// Given an `IpAddress`, converts it to an `Ip4Address` directly, or from + /// an IPv4-mapped IPv6 address, or returns `null`. + pub fn fromAny(addr: IpAddress) ?Ip6Address { + return switch (addr) { + .ip4 => |ip4| ip4, + .ip6 => |ip6| fromIp6(ip6), + }; + } + pub const ParseError = error{ Overflow, InvalidEnd, @@ -429,9 +458,8 @@ pub const Ip6Address = struct { /// Constructs an IPv4-mapped IPv6 address. pub fn fromIp4(ip4: Ip4Address) Ip6Address { - const b = &ip4.bytes; return .{ - .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, b[0], b[1], b[2], b[3] }, + .bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff } ++ ip4.bytes, .port = ip4.port, }; } @@ -572,19 +600,6 @@ pub const Ip6Address = struct { } } - pub const FromAddressError = Interface.NameError; - - pub fn fromAddress(a: *const Ip6Address, io: Io) FromAddressError!Unresolved { - if (a.interface.isNone()) return .{ - .bytes = a.bytes, - .interface_name = null, - }; - return .{ - .bytes = a.bytes, - .interface_name = try a.interface.name(io), - }; - } - pub fn format(u: *const Unresolved, w: *Io.Writer) Io.Writer.Error!void { const bytes = &u.bytes; if (std.mem.eql(u8, bytes[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { @@ -629,20 +644,13 @@ pub const Ip6Address = struct { } var i: usize = 0; - var abbrv = false; - while (i < parts.len) : (i += 1) { + while (parts.len - i != 0) : (i += 1) { if (i == longest_start) { // Emit "::" for the longest zero run - if (!abbrv) { - try w.writeAll(if (i == 0) "::" else ":"); - abbrv = true; - } + try w.writeAll(if (i == 0) "::" else ":"); i += longest_len - 1; // Skip the compressed range continue; } - if (abbrv) { - abbrv = false; - } try w.print("{x}", .{parts[i]}); if (i != parts.len - 1) { try w.writeAll(":"); @@ -704,24 +712,25 @@ pub const Ip6Address = struct { }; } - pub const FormatError = Io.Writer.Error || Unresolved.FromAddressError; + pub const FormatError = Io.Writer.Error || Interface.NameError; /// Includes the optional scope ("%foo" at the end). /// /// See `format` for an alternative that omits scopes and does /// not require an `Io` parameter. - pub fn formatResolved(a: Ip6Address, io: Io, w: *Io.Writer) FormatError!void { - const u: Unresolved = try .fromAddress(io); + pub fn formatResolved(a: *const Ip6Address, io: Io, w: *Io.Writer) FormatError!void { + const interface_name = if (a.interface.isNone()) null else try a.interface.name(io); + const u: Unresolved = .{ + .bytes = a.bytes, + .interface_name = if (interface_name) |name| name.toSlice() else null, + }; try w.print("[{f}]:{d}", .{ u, a.port }); } /// See `formatResolved` for an alternative that additionally prints the optional /// scope at the end of addresses and requires an `Io` parameter. - pub fn format(a: Ip6Address, w: *Io.Writer) Io.Writer.Error!void { - const u: Unresolved = .{ - .bytes = a.bytes, - .interface_name = null, - }; + pub fn format(a: *const Ip6Address, w: *Io.Writer) Io.Writer.Error!void { + const u: Unresolved = .{ .bytes = a.bytes, .interface_name = null }; try w.print("[{f}]:{d}", .{ u, a.port }); } @@ -825,7 +834,10 @@ pub const Ip6Address = struct { pub const UnixAddress = struct { path: []const u8, - pub const max_len = 108; + pub const max_len = switch (native_os) { + .windows => std.os.windows.PATH_MAX_WIDE, + else => 108, + }; pub const InitError = error{NameTooLong}; @@ -834,6 +846,10 @@ pub const UnixAddress = struct { return .{ .path = p }; } + pub fn isAbstract(ua: *const UnixAddress) bool { + return ua.path.len == 0 or ua.path[0] == 0; + } + pub const ListenError = error{ AddressFamilyUnsupported, AddressInUse, @@ -859,10 +875,13 @@ pub const UnixAddress = struct { pub fn listen(ua: *const UnixAddress, io: Io, options: ListenOptions) ListenError!Server { assert(ua.path.len <= max_len); - return .{ .socket = .{ - .handle = try io.vtable.netListenUnix(io.userdata, ua, options), - .address = .{ .ip4 = .loopback(0) }, - } }; + return .{ + .socket = .{ + .handle = try io.vtable.netListenUnix(io.userdata, ua, options), + .address = .{ .ip4 = .loopback(0) }, + }, + .options = if (Server.AcceptOptions != void) .{ .mode = .stream, .protocol = null }, + }; } pub const ConnectError = error{ @@ -871,7 +890,6 @@ pub const UnixAddress = struct { SystemFdQuotaExceeded, AddressFamilyUnsupported, ProtocolUnsupportedBySystem, - ProtocolUnsupportedByAddressFamily, SocketModeUnsupported, AccessDenied, PermissionDenied, @@ -1006,7 +1024,12 @@ pub const Interface = struct { } }; - pub const NameError = Io.UnexpectedError || Io.Cancelable; + pub const NameError = error{ + /// Out of range `index`. + InterfaceNotFound, + /// Interface name longer than `Name.max_len`. + NameTooLong, + } || Io.UnexpectedError || Io.Cancelable; /// Asserts not `none`. /// @@ -1047,10 +1070,7 @@ pub const Socket = struct { /// Underlying platform-defined type which may or may not be /// interchangeable with a file system file descriptor. - pub const Handle = switch (native_os) { - .windows => std.os.windows.ws2_32.SOCKET, - else => std.posix.fd_t, - }; + pub const Handle = std.posix.fd_t; /// Leaves `address` in a valid state. pub fn close(s: *const Socket, io: Io) void { @@ -1377,6 +1397,7 @@ pub const Stream = struct { pub const Server = struct { socket: Socket, + options: AcceptOptions, pub fn deinit(s: *Server, io: Io) void { s.socket.close(io); @@ -1408,9 +1429,14 @@ pub const Server = struct { ProtocolFailure, } || Io.UnexpectedError || Io.Cancelable; + pub const AcceptOptions = switch (native_os) { + .windows => struct { mode: Socket.Mode, protocol: ?Protocol }, + else => void, + }; + /// Blocks until a client connects to the server. pub fn accept(s: *Server, io: Io) AcceptError!Stream { - return io.vtable.netAccept(io.userdata, s.socket.handle); + return .{ .socket = try io.vtable.netAccept(io.userdata, s.socket.handle, s.options) }; } }; diff --git a/lib/std/Io/net/HostName.zig b/lib/std/Io/net/HostName.zig index 174d95f886..5202f72fda 100644 --- a/lib/std/Io/net/HostName.zig +++ b/lib/std/Io/net/HostName.zig @@ -125,6 +125,7 @@ pub fn eql(a: HostName, b: HostName) bool { pub const LookupOptions = struct { port: u16, + request_canonical_name: bool = false, canonical_name_buffer: *[max_len]u8, /// `null` means either. family: ?IpAddress.Family = null, diff --git a/lib/std/Io/net/test.zig b/lib/std/Io/net/test.zig index 75bdf17b9c..e601869191 100644 --- a/lib/std/Io/net/test.zig +++ b/lib/std/Io/net/test.zig @@ -85,7 +85,7 @@ test "IPv6 address parse failures" { } test "invalid but parseable IPv6 scope ids" { - if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) return error.SkipZigTest; + if (builtin.os.tag != .linux and builtin.os.tag != .windows and comptime !builtin.os.tag.isDarwin()) return error.SkipZigTest; const io = testing.io; @@ -129,6 +129,7 @@ test "resolve DNS" { net.HostName.lookup(try .init("localhost"), io, &results, .{ .port = 80, + .request_canonical_name = true, .canonical_name_buffer = &canonical_name_buffer, }) catch |err| switch (err) { error.NetworkDown => return error.SkipZigTest, @@ -142,7 +143,8 @@ test "resolve DNS" { if (address.eql(&localhost_v4) or address.eql(&localhost_v6)) addresses_found += 1; }, - .canonical_name => |canonical_name| try testing.expectEqualStrings("localhost", canonical_name.bytes), + .canonical_name => |canonical_name| if (builtin.os.tag == .linux) + try testing.expectEqualStrings("localhost", canonical_name.bytes), } else |err| switch (err) { error.Closed => {}, error.Canceled => |e| return e, @@ -234,11 +236,6 @@ test "listen on an in use port" { } test "listen on a unix socket, send bytes, receive bytes" { - if (builtin.os.tag == .windows) { - // https://codeberg.org/ziglang/zig/issues/31499 - return error.SkipZigTest; - } - const io = testing.io; const gpa = testing.allocator; @@ -345,11 +342,6 @@ test "decompress compressed DNS name" { } test "cancel accept" { - if (builtin.os.tag == .windows) { - // https://codeberg.org/ziglang/zig/issues/30865 - return error.SkipZigTest; - } - const io = testing.io; const localhost: net.IpAddress = .{ .ip4 = .loopback(0) }; diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index aee7602bf5..aa9c9f54be 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -743,6 +743,7 @@ fn windowsApiWriteMarker(io: Io) WindowsApiError!void { }, 0, .{})), } })).device_io_control.u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, else => |status| return windows.unexpectedStatus(status), } } @@ -970,6 +971,7 @@ fn windowsApiMoveToMarker(io: Io, nl_n: usize) WindowsApiError!void { })), } })).device_io_control.u.Status) { .SUCCESS => {}, + .CANCELLED => unreachable, else => |status| return windows.unexpectedStatus(status), } if (read_output_char.Data.nLength >= 1 and buffer[0] == windows_api_start_marker) break; diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index b729cbe359..d8760195fe 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -560,9 +560,9 @@ const WindowsThreadImpl = struct { }, }; - // Windows appears to only support SYSTEM_INFO.dwAllocationGranularity minimum stack size. - // Going lower makes it default to that specified in the executable (~1mb). - // Its also fine if the limit here is incorrect as stack size is only a hint. + // Windows appears to only support SYSTEM.BASIC_INFORMATION.AllocationGranularity + // minimum stack size. Going lower makes it default to that specified in the executable + // (~1mb). Its also fine if the limit here is incorrect as stack size is only a hint. const stack_size = @max(64 * 1024, std.math.lossyCast(u32, config.stack_size)); // Intended to be equivalent to a kernel32.CreateThread call with no flags set. @@ -1741,6 +1741,6 @@ pub fn maybeAttachSignalStack() void { }, null) catch |err| switch (err) { error.SizeTooSmall => unreachable, // `std.options.signal_stack_size` must be sufficient for the target error.PermissionDenied => unreachable, // called `maybeAttachSignalStack` from a signal handler - error.Unexpected => @panic("unexpected error attaching signal stack"), + error.Unexpected => unreachable, }; } diff --git a/lib/std/c.zig b/lib/std/c.zig index 8251b17913..e130df1672 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -10807,9 +10807,6 @@ pub extern "c" fn recvfrom( ) if (native_os == .windows) c_int else isize; pub const recvmsg = switch (native_os) { - // Technically, a form of recvmsg() exists for Windows, but the user has to - // install some kind of callback for it. - // https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg .windows => {}, else => private.recvmsg, }; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 7cac79d727..4c46f7d0c4 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -576,6 +576,7 @@ fn loadNtdllProc(si: *SelfInfo, name: []const u8) Io.UnexpectedError!*anyopaque &.{ 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l' }, ), &ntdll_handle)) { .SUCCESS => {}, + .DLL_NOT_FOUND => return error.Unexpected, else => |status| return windows.unexpectedStatus(status), } si.ntdll_handle = ntdll_handle; diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 4ad01dff3f..5da13b18fc 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -598,6 +598,14 @@ pub const FILE = struct { CurrentByteOffset: LARGE_INTEGER, }; + pub const FULL_EA_INFORMATION = extern struct { + NextEntryOffset: ULONG, + Flags: UCHAR, + EaNameLength: UCHAR, + EaValueLength: USHORT, + EaName: [0]CHAR, + }; + pub const FS_DEVICE_INFORMATION = extern struct { DeviceType: DEVICE_TYPE, Characteristics: ULONG, @@ -864,8 +872,6 @@ pub const FILE = struct { Mode: MODE, }; }; - - // ref: km/ }; pub const DIRECTORY = struct { @@ -1108,6 +1114,865 @@ pub const CONSOLE = struct { }; }; +pub const AFD = packed struct(ULONG) { + NO_FAST_IO: bool = false, + OVERLAPPED: bool = false, + Reserved0: u30 = 0, + + pub const Mutability = enum { @"const", @"var" }; + pub fn WSABUF(comptime mutability: Mutability) type { + return extern struct { + len: ULONG, + buf: switch (mutability) { + .@"const" => [*]const u8, + .@"var" => [*]u8, + }, + }; + } + pub const GUARANTEE = enum(c_int) { + BestEffort, + ControlledLoad, + Predictive, + GuaranteedDelay, + Guaranteed, + _, + }; + pub const DEVICE_NAME: []const u16 = &.{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'A', 'f', 'd' }; + pub const ENDPOINT_TYPE = packed struct(ULONG) { + CONNECTIONLESS: bool = false, + Reserved1: u3 = 0, + MESSAGEMODE: bool = false, + Reserved5: u3 = 0, + RAW: bool = false, + Reserved9: u22 = 0, + REGISTERED_IO: bool = false, + }; + pub const OPEN_PACKET = extern struct { + EndpointType: ENDPOINT_TYPE, + GroupID: LONG, + AddressFamily: LONG, + SocketType: LONG, + Protocol: LONG, + TransportDeviceNameLength: ULONG, + TransportDeviceName: [1]WCHAR, + + pub const NAME = "AfdOpenPacketXX"; + + pub const FULL_EA_INFORMATION = extern struct { + Header: FILE.FULL_EA_INFORMATION = .{ + .NextEntryOffset = 0, + .Flags = 0, + .EaNameLength = NAME.len, + .EaValueLength = @sizeOf(OPEN_PACKET), + .EaName = .{}, + }, + Name: [NAME.len:0]u8 = NAME.*, + Value: OPEN_PACKET, + }; + }; + pub const BIND_INFO = extern struct { + Mode: MODE, + + pub const MODE = enum(ULONG) { + Unix = 0, + Passive = 1, + Active = 2, + _, + }; + }; + pub const LISTEN_INFO = extern struct { + UseSAN: BOOLEAN, + MaximumConnectionQueue: ULONG, + UseDelayedAcceptance: BOOLEAN, + }; + pub const LISTEN_RESPONSE_INFO = extern struct { + Sequence: ULONG, + }; + pub const ACCEPT_INFO = extern struct { + UseSAN: BOOLEAN, + Sequence: ULONG, + AcceptHandle: HANDLE, + }; + pub const SUPER_ACCEPT_INFO = extern struct { + UseSAN: BOOLEAN, + AcceptHandle: HANDLE, + AcceptEndpoint: PVOID, + AcceptFileObject: PVOID, + ReceiveDataLength: ULONG, + LocalAddressLength: ULONG, + RemoteAddressLength: ULONG, + ListenResponseInfo: LISTEN_RESPONSE_INFO, + }; + pub const DEFER_ACCEPT_INFO = extern struct { + Sequence: ULONG, + Reject: BOOLEAN, + }; + pub const PARTIAL_DISCONNECT_INFO = extern struct { + DisconnectMode: MODE, + Timeout: LARGE_INTEGER, + + pub const MODE = packed struct(ULONG) { + SEND: bool = false, + RECEIVE: bool = false, + ABORTIVE: bool = false, + UNCONNECT_DATAGRAM: bool = false, + Reserved4: u28 = 0, + }; + }; + pub const RECEIVE_INFORMATION = extern struct { + BytesAvailable: ULONG, + ExpeditedBytesAvailable: ULONG, + }; + pub const HANDLE_INFO = extern struct { + TdiAddressHandle: HANDLE, + TdiConnectionHandle: HANDLE, + }; + pub const INFORMATION = extern struct { + InformationType: TYPE, + Information: extern union { + Boolean: BOOLEAN, + Ulong: ULONG, + LargeInteger: LARGE_INTEGER, + }, + + pub const TYPE = enum(ULONG) { + INLINE_MODE = 0x01, + NONBLOCKING_MODE = 0x02, + MAX_SEND_SIZE = 0x03, + SENDS_PENDING = 0x04, + MAX_PATH_SEND_SIZE = 0x05, + RECEIVE_WINDOW_SIZE = 0x06, + SEND_WINDOW_SIZE = 0x07, + CONNECT_TIME = 0x08, + CIRCULAR_QUEUEING = 0x09, + GROUP_ID_AND_TYPE = 0x0A, + _, + }; + }; + pub const TRANSMIT_FILE_INFO = extern struct { + Offset: LARGE_INTEGER, + WriteLength: LARGE_INTEGER, + SendPacketLength: ULONG, + FileHandle: HANDLE, + Head: PVOID, + HeadLength: ULONG, + Tail: PVOID, + TailLength: ULONG, + Flags: FLAGS, + + pub const FLAGS = packed struct(ULONG) { + DISCONNECT: bool = false, + REUSE_SOCKET: bool = false, + WRITE_BEHIND: bool = false, + Reserved3: u25 = 0, + }; + }; + pub const QUEUE_APC_INFO = extern struct { + Thread: HANDLE, + ApcRoutine: PVOID, + ApcContext: PVOID, + SystemArgument1: PVOID, + SystemArgument2: PVOID, + }; + pub const SEND_INFO = extern struct { + BufferArray: [*]const WSABUF(.@"const"), + BufferCount: ULONG, + AfdFlags: AFD, + TdiFlags: TDI.SEND, + }; + pub const SEND_DATAGRAM_INFO = extern struct { + BufferArray: [*]const WSABUF(.@"const"), + BufferCount: ULONG, + AfdFlags: AFD, + TdiRequest: TDI.REQUEST.SEND_DATAGRAM, + TdiConnInfo: TDI.CONNECTION.INFORMATION, + }; + pub const RECV_INFO = extern struct { + BufferArray: [*]const WSABUF(.@"var"), + BufferCount: ULONG, + AfdFlags: AFD, + TdiFlags: TDI.RECEIVE, + }; + pub const RECV_DATAGRAM_INFO = extern struct { + BufferArray: [*]const WSABUF(.@"var"), + BufferCount: ULONG, + AfdFlags: AFD, + TdiFlags: TDI.RECEIVE, + Address: PVOID, + AddressLength: *ULONG, + }; + pub const SOCKOPT_INFO = extern struct { + mode: Mode, + level: i32, + optname: u32, + ding: u32 = 1, + optval: *const anyopaque, + optlen: usize, + + pub const Mode = enum(u32) { set = 1, get = 2, special = 3, _ }; + + pub const UNIX_PATH = extern struct { Unknown0: usize = 0, Path: [PATH_MAX_WIDE:0]u16 }; + }; +}; + +pub const TDI = struct { + pub const STATUS = NTSTATUS; + pub const CONNECTION = struct { + pub const CONTEXT = PVOID; + pub const INFORMATION = extern struct { + /// length of user data buffer + UserDataLength: LONG, + /// pointer to user data buffer + UserData: PVOID, + /// length of following buffer + OptionsLength: LONG, + /// pointer to buffer containing options + Options: PVOID, + /// length of following buffer + RemoteAddressLength: LONG, + /// buffer containing the remote address + RemoteAddress: PVOID, + }; + }; + pub const ADDRESS = struct { + pub const TYPE = enum(USHORT) { + /// unspecified + UNSPEC = 0, + /// local to host (pipes, portals, + UNIX = 1, + /// internetwork: UDP, TCP, etc. + IP = 2, + /// arpanet imp addresses + IMPLINK = 3, + /// pup protocols: e.g. BSP + PUP = 4, + /// mit CHAOS protocols + CHAOS = 5, + /// XEROX NS protocols + NS = 6, + /// Netware IPX + IPX = 6, + /// nbs protocols + NBS = 7, + /// european computer manufacturers + ECMA = 8, + /// datakit protocols + DATAKIT = 9, + /// CCITT protocols, X.25 etc + CCITT = 10, + /// IBM SNA + SNA = 11, + /// DECnet + DECnet = 12, + /// Direct data link interface + DLI = 13, + /// LAT + LAT = 14, + /// NSC Hyperchannel + HYLINK = 15, + /// AppleTalk + APPLETALK = 16, + /// Netbios Addresses + NETBIOS = 17, + @"8022" = 18, + OSI_TSAP = 19, + /// for WzMail + NETONE = 20, + /// Banyan VINES IP + VNS = 21, + /// NETBIOS address extensions + NETBIOS_EX = 22, + /// IP version 6 + IP6 = 23, + /// WCHAR Netbios address + NETBIOS_UNICODE_EX = 24, + _, + }; + pub const IP = extern struct { + sin_port: USHORT, + in_addr: ULONG, + sin_zero: [8]UCHAR, + }; + pub const IP6 = extern struct { + sin_port: USHORT, + flowinfo: ULONG, + addr: [8]USHORT, + scope_id: ULONG, + }; + }; + pub const REQUEST = extern struct { + Handle: extern union { + AddressHandle: HANDLE, + ConnectionContext: CONNECTION.CONTEXT, + ControlChannel: HANDLE, + }, + RequestNotifyObject: PVOID, + RequestContext: PVOID, + TdiStatus: TDI.STATUS, + + pub const STATUS = extern struct { + /// status of request completion + Status: TDI.STATUS, + /// the request context + RequestContext: PVOID, + /// number of bytes transferred in the request + BytesTransferred: ULONG, + }; + pub const ASSOCIATE = extern struct { + Request: REQUEST, + AddressHandle: HANDLE, + }; + pub const CONNECT = extern struct { + Request: REQUEST, + RequestConnectionInformation: *CONNECTION.INFORMATION, + ReturnConnectionInformation: *CONNECTION.INFORMATION, + Timeout: LARGE_INTEGER, + }; + pub const ACCEPT = extern struct { + Request: REQUEST, + RequestConnectionInformation: *CONNECTION.INFORMATION, + ReturnConnectionInformation: *CONNECTION.INFORMATION, + }; + pub const LISTEN = extern struct { + Request: REQUEST, + RequestConnectionInformation: *CONNECTION.INFORMATION, + ReturnConnectionInformation: *CONNECTION.INFORMATION, + ListenFlags: USHORT, + }; + pub const DISCONNECT = extern struct { + Request: REQUEST, + Timeout: LARGE_INTEGER, + }; + pub const SEND = extern struct { + Request: REQUEST, + SendFlags: USHORT, + }; + pub const RECEIVE = extern struct { + Request: REQUEST, + ReceiveFlags: USHORT, + }; + pub const SEND_DATAGRAM = extern struct { + Request: REQUEST, + SendDatagramInformation: *CONNECTION.INFORMATION, + }; + }; + pub const RECEIVE = packed struct(ULONG) { + Reserved0: u2 = 0, + BROADCAST: bool = false, + MULTICAST: bool = false, + PARTIAL: bool = false, + NORMAL: bool = false, + EXPEDITED: bool = false, + PEEK: bool = false, + NO_RESPONSE_EXP: bool = false, + COPY_LOOKAHEAD: bool = false, + ENTIRE_MESSAGE: bool = false, + AT_DISPATCH_LEVEL: bool = false, + CONTROL_INFO: bool = false, + FORCE_INDICATION: bool = false, + NO_PUSH: bool = false, + Reserved12: u17 = 0, + }; + pub const SEND = packed struct(ULONG) { + Reserved0: u5 = 0, + EXPEDITED: bool = false, + PARTIAL: bool = false, + NO_RESPONSE_EXPECTED: bool = false, + NON_BLOCKING: bool = false, + AND_DISCONNECT: bool = false, + Reserved10: u22 = 0, + }; +}; + +pub const NET = struct { + pub const LUID = packed struct(ULONG64) { Reserved: u24 = 0, Index: u24, IfType: u16 }; + pub const IFINDEX = enum(ULONG) { _ }; +}; + +pub const DNS = struct { + pub const INTERFACE_SETTINGS = extern struct { + Version: ULONG, + Flags: ULONG64, + Domain: PWSTR, + NameServer: PWSTR, + SearchList: PWSTR, + RegistrationEnabled: ULONG, + RegisterAdapterName: ULONG, + EnableLLMNR: ULONG, + QueryAdapterName: ULONG, + ProfileNameServer: PWSTR, + }; + + // ref: shared/windnsdef.h + + pub const ADDR_MAX_SOCKADDR_LENGTH = 32; + + pub const ADDR = extern struct { + MaxSa: [ADDR_MAX_SOCKADDR_LENGTH]CHAR, + DnsAddrUserDword: [8]DWORD, + + pub const ARRAY = extern struct { + MaxCount: DWORD, + AddrCount: DWORD, + Tag: DWORD, + Family: WORD, + WordReserved: WORD, + Flags: DWORD, + MatchFlag: DWORD, + Reserved1: DWORD, + Reserved2: DWORD, + AddrArray: [0]ADDR, + }; + }; + + pub const CUSTOM_SERVER = extern struct { + ServerType: CUSTOM_SERVER.TYPE, + Flags: FLAGS, + Info: extern union { + UDP: void, + DOH: extern struct { Template: PWSTR }, + DOT: extern struct { Hostname: PWSTR }, + }, + MaxSa: [ADDR_MAX_SOCKADDR_LENGTH]CHAR, + + pub const TYPE = enum(DWORD) { UDP = 0x1, DOH = 0x2, DOT = 0x3, _ }; + pub const FLAGS = packed struct(ULONG64) { + UDP_FALLBACK: bool = false, + UPGRADE_FROM_WELL_KNOWN_SERVERS: bool = false, + Reserved2: u62 = 0, + }; + }; + + // ref: um/WinDNS.h + + pub const STATUS = enum(LONG) { + /// The operation completed successfully. + SUCCESS = 0, + /// The parameter is incorrect. + INVALID_PARAMETER = 87, + /// The filename, directory name, or volume label syntax is incorrect. + INVALID_NAME = 123, + /// DNS server unable to interpret format. + FORMAT_ERROR = 9001, + /// DNS server failure. + SERVER_FAILURE = 9002, + /// DNS name does not exist. + NAME_ERROR = 9003, + /// DNS request not supported by name server. + NOT_IMPLEMENTED = 9004, + /// DNS operation refused. + REFUSED = 9005, + /// DNS name that ought not exist, does exist. + YXDOMAIN = 9006, + /// DNS RR set that ought not exist, does exist. + YXRRSET = 9007, + /// DNS RR set that ought to exist, does not exist. + NXRRSET = 9008, + /// DNS server not authoritative for zone. + NOTAUTH = 9009, + /// DNS name in update or prereq is not in zone. + NOTZONE = 9010, + /// DNS signature failed to verify. + BADSIG = 9016, + /// DNS bad key. + BADKEY = 9017, + /// DNS signature validity expired. + BADTIME = 9018, + /// Only the DNS server acting as the key master for the zone may perform this operation. + KEYMASTER_REQUIRED = 9101, + /// This operation is not allowed on a zone that is signed or has signing keys. + NOT_ALLOWED_ON_SIGNED_ZONE = 9102, + /// NSEC3 is not compatible with the RSA-SHA-1 algorithm. Choose a different algorithm or use NSEC. + /// + /// This value was also named DNS_INVALID_NSEC3_PARAMETERS + NSEC3_INCOMPATIBLE_WITH_RSA_SHA1 = 9103, + /// The zone does not have enough signing keys. There must be at least one key signing key (KSK) and at least one zone signing key (ZSK). + NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS = 9104, + /// The specified algorithm is not supported. + UNSUPPORTED_ALGORITHM = 9105, + /// The specified key size is not supported. + INVALID_KEY_SIZE = 9106, + /// One or more of the signing keys for a zone are not accessible to the DNS server. Zone signing will not be operational until this error is resolved. + SIGNING_KEY_NOT_ACCESSIBLE = 9107, + /// The specified key storage provider does not support DPAPI++ data protection. Zone signing will not be operational until this error is resolved. + KSP_DOES_NOT_SUPPORT_PROTECTION = 9108, + /// An unexpected DPAPI++ error was encountered. Zone signing will not be operational until this error is resolved. + UNEXPECTED_DATA_PROTECTION_ERROR = 9109, + /// An unexpected crypto error was encountered. Zone signing may not be operational until this error is resolved. + UNEXPECTED_CNG_ERROR = 9110, + /// The DNS server encountered a signing key with an unknown version. Zone signing will not be operational until this error is resolved. + UNKNOWN_SIGNING_PARAMETER_VERSION = 9111, + /// The specified key service provider cannot be opened by the DNS server. + KSP_NOT_ACCESSIBLE = 9112, + /// The DNS server cannot accept any more signing keys with the specified algorithm and KSK flag value for this zone. + TOO_MANY_SKDS = 9113, + /// The specified rollover period is invalid. + INVALID_ROLLOVER_PERIOD = 9114, + /// The specified initial rollover offset is invalid. + INVALID_INITIAL_ROLLOVER_OFFSET = 9115, + /// The specified signing key is already in process of rolling over keys. + ROLLOVER_IN_PROGRESS = 9116, + /// The specified signing key does not have a standby key to revoke. + STANDBY_KEY_NOT_PRESENT = 9117, + /// This operation is not allowed on a zone signing key (ZSK). + NOT_ALLOWED_ON_ZSK = 9118, + /// This operation is not allowed on an active signing key. + NOT_ALLOWED_ON_ACTIVE_SKD = 9119, + /// The specified signing key is already queued for rollover. + ROLLOVER_ALREADY_QUEUED = 9120, + /// This operation is not allowed on an unsigned zone. + NOT_ALLOWED_ON_UNSIGNED_ZONE = 9121, + /// This operation could not be completed because the DNS server listed as the current key master for this zone is down or misconfigured. Resolve the problem on the current key master for this zone or use another DNS server to seize the key master role. + BAD_KEYMASTER = 9122, + /// The specified signature validity period is invalid. + INVALID_SIGNATURE_VALIDITY_PERIOD = 9123, + /// The specified NSEC3 iteration count is higher than allowed by the minimum key length used in the zone. + INVALID_NSEC3_ITERATION_COUNT = 9124, + /// This operation could not be completed because the DNS server has been configured with DNSSEC features disabled. Enable DNSSEC on the DNS server. + DNSSEC_IS_DISABLED = 9125, + /// This operation could not be completed because the XML stream received is empty or syntactically invalid. + INVALID_XML = 9126, + /// This operation completed, but no trust anchors were added because all of the trust anchors received were either invalid, unsupported, expired, or would not become valid in less than 30 days. + NO_VALID_TRUST_ANCHORS = 9127, + /// The specified signing key is not waiting for parental DS update. + ROLLOVER_NOT_POKEABLE = 9128, + /// Hash collision detected during NSEC3 signing. Specify a different user-provided salt, or use a randomly generated salt, and attempt to sign the zone again. + NSEC3_NAME_COLLISION = 9129, + /// NSEC is not compatible with the NSEC3-RSA-SHA-1 algorithm. Choose a different algorithm or use NSEC3. + NSEC_INCOMPATIBLE_WITH_NSEC3_RSA_SHA1 = 9130, + /// No records found for given DNS query. + NO_RECORDS = 9501, + /// Bad DNS packet. + BAD_PACKET = 9502, + /// No DNS packet. + NO_PACKET = 9503, + /// DNS error, check rcode. + RCODE = 9504, + /// Unsecured DNS packet. + UNSECURE_PACKET = 9505, + /// DNS query request is pending. + REQUEST_PENDING = 9506, + /// Invalid DNS type. + INVALID_TYPE = 9551, + /// Invalid IP address. + INVALID_IP_ADDRESS = 9552, + /// Invalid property. + INVALID_PROPERTY = 9553, + /// Try DNS operation again later. + TRY_AGAIN_LATER = 9554, + /// Record for given name and type is not unique. + NOT_UNIQUE = 9555, + /// DNS name does not comply with RFC specifications. + NON_RFC_NAME = 9556, + /// DNS name is a fully-qualified DNS name. + FQDN = 9557, + /// DNS name is dotted (multi-label). + DOTTED_NAME = 9558, + /// DNS name is a single-part name. + SINGLE_PART_NAME = 9559, + /// DNS name contains an invalid character. + INVALID_NAME_CHAR = 9560, + /// DNS name is entirely numeric. + NUMERIC_NAME = 9561, + /// The operation requested is not permitted on a DNS root server. + NOT_ALLOWED_ON_ROOT_SERVER = 9562, + /// The record could not be created because this part of the DNS namespace has been delegated to another server. + NOT_ALLOWED_UNDER_DELEGATION = 9563, + /// The DNS server could not find a set of root hints. + CANNOT_FIND_ROOT_HINTS = 9564, + /// The DNS server found root hints but they were not consistent across all adapters. + INCONSISTENT_ROOT_HINTS = 9565, + /// The specified value is too small for this parameter. + DWORD_VALUE_TOO_SMALL = 9566, + /// The specified value is too large for this parameter. + DWORD_VALUE_TOO_LARGE = 9567, + /// This operation is not allowed while the DNS server is loading zones in the background. Please try again later. + BACKGROUND_LOADING = 9568, + /// The operation requested is not permitted on against a DNS server running on a read-only DC. + NOT_ALLOWED_ON_RODC = 9569, + /// No data is allowed to exist underneath a DNAME record. + NOT_ALLOWED_UNDER_DNAME = 9570, + /// This operation requires credentials delegation. + DELEGATION_REQUIRED = 9571, + /// Name resolution policy table has been corrupted. DNS resolution will fail until it is fixed. Contact your network administrator. + INVALID_POLICY_TABLE = 9572, + /// DNS zone does not exist. + ZONE_DOES_NOT_EXIST = 9601, + /// DNS zone information not available. + NO_ZONE_INFO = 9602, + /// Invalid operation for DNS zone. + INVALID_ZONE_OPERATION = 9603, + /// Invalid DNS zone configuration. + ZONE_CONFIGURATION_ERROR = 9604, + /// DNS zone has no start of authority (SOA) record. + ZONE_HAS_NO_SOA_RECORD = 9605, + /// DNS zone has no Name Server (NS) record. + ZONE_HAS_NO_NS_RECORDS = 9606, + /// DNS zone is locked. + ZONE_LOCKED = 9607, + /// DNS zone creation failed. + ZONE_CREATION_FAILED = 9608, + /// DNS zone already exists. + ZONE_ALREADY_EXISTS = 9609, + /// DNS automatic zone already exists. + AUTOZONE_ALREADY_EXISTS = 9610, + /// Invalid DNS zone type. + INVALID_ZONE_TYPE = 9611, + /// Secondary DNS zone requires master IP address. + SECONDARY_REQUIRES_MASTER_IP = 9612, + /// DNS zone not secondary. + ZONE_NOT_SECONDARY = 9613, + /// Need secondary IP address. + NEED_SECONDARY_ADDRESSES = 9614, + /// WINS initialization failed. + WINS_INIT_FAILED = 9615, + /// Need WINS servers. + NEED_WINS_SERVERS = 9616, + /// NBTSTAT initialization call failed. + NBSTAT_INIT_FAILED = 9617, + /// Invalid delete of start of authority (SOA). + SOA_DELETE_INVALID = 9618, + /// A conditional forwarding zone already exists for that name. + FORWARDER_ALREADY_EXISTS = 9619, + /// This zone must be configured with one or more master DNS server IP addresses. + ZONE_REQUIRES_MASTER_IP = 9620, + /// The operation cannot be performed because this zone is shut down. + ZONE_IS_SHUTDOWN = 9621, + /// This operation cannot be performed because the zone is currently being signed. Please try again later. + ZONE_LOCKED_FOR_SIGNING = 9622, + /// Primary DNS zone requires datafile. + PRIMARY_REQUIRES_DATAFILE = 9651, + /// Invalid datafile name for DNS zone. + INVALID_DATAFILE_NAME = 9652, + /// Failed to open datafile for DNS zone. + DATAFILE_OPEN_FAILURE = 9653, + /// Failed to write datafile for DNS zone. + FILE_WRITEBACK_FAILED = 9654, + /// Failure while reading datafile for DNS zone. + DATAFILE_PARSING = 9655, + /// DNS record does not exist. + RECORD_DOES_NOT_EXIST = 9701, + /// DNS record format error. + RECORD_FORMAT = 9702, + /// Node creation failure in DNS. + NODE_CREATION_FAILED = 9703, + /// Unknown DNS record type. + UNKNOWN_RECORD_TYPE = 9704, + /// DNS record timed out. + RECORD_TIMED_OUT = 9705, + /// Name not in DNS zone. + NAME_NOT_IN_ZONE = 9706, + /// CNAME loop detected. + CNAME_LOOP = 9707, + /// Node is a CNAME DNS record. + NODE_IS_CNAME = 9708, + /// A CNAME record already exists for given name. + CNAME_COLLISION = 9709, + /// Record only at DNS zone root. + RECORD_ONLY_AT_ZONE_ROOT = 9710, + /// DNS record already exists. + RECORD_ALREADY_EXISTS = 9711, + /// Secondary DNS zone data error. + SECONDARY_DATA = 9712, + /// Could not create DNS cache data. + NO_CREATE_CACHE_DATA = 9713, + /// DNS name does not exist. + NAME_DOES_NOT_EXIST = 9714, + /// Could not create pointer (PTR) record. + PTR_CREATE_FAILED = 9715, + /// DNS domain was undeleted. + DOMAIN_UNDELETED = 9716, + /// The directory service is unavailable. + DS_UNAVAILABLE = 9717, + /// DNS zone already exists in the directory service. + DS_ZONE_ALREADY_EXISTS = 9718, + /// DNS server not creating or reading the boot file for the directory service integrated DNS zone. + NO_BOOTFILE_IF_DS_ZONE = 9719, + /// Node is a DNAME DNS record. + NODE_IS_DNAME = 9720, + /// A DNAME record already exists for given name. + DNAME_COLLISION = 9721, + /// An alias loop has been detected with either CNAME or DNAME records. + ALIAS_LOOP = 9722, + /// DNS AXFR (zone transfer) complete. + AXFR_COMPLETE = 9751, + /// DNS zone transfer failed. + AXFR = 9752, + /// Added local WINS server. + ADDED_LOCAL_WINS = 9753, + /// Secure update call needs to continue update request. + CONTINUE_NEEDED = 9801, + /// TCP/IP network protocol not installed. + NO_TCPIP = 9851, + /// No DNS servers configured for local system. + NO_DNS_SERVERS = 9852, + /// The specified directory partition does not exist. + DP_DOES_NOT_EXIST = 9901, + /// The specified directory partition already exists. + DP_ALREADY_EXISTS = 9902, + /// This DNS server is not enlisted in the specified directory partition. + DP_NOT_ENLISTED = 9903, + /// This DNS server is already enlisted in the specified directory partition. + DP_ALREADY_ENLISTED = 9904, + /// The directory partition is not available at this time. Please wait a few minutes and try again. + DP_NOT_AVAILABLE = 9905, + /// The operation failed because the domain naming master FSMO role could not be reached. The domain controller holding the domain naming master FSMO role is down or unable to service the request or is not running Windows Server 2003 or later. + DP_FSMO_ERROR = 9906, + _, + }; + + pub const TYPE = enum(WORD) { + A = 0x0001, + NS = 0x0002, + MD = 0x0003, + MF = 0x0004, + CNAME = 0x0005, + SOA = 0x0006, + MB = 0x0007, + MG = 0x0008, + MR = 0x0009, + NULL = 0x000a, + WKS = 0x000b, + PTR = 0x000c, + HINFO = 0x000d, + MINFO = 0x000e, + MX = 0x000f, + TEXT = 0x0010, + RP = 0x0011, + AFSDB = 0x0012, + X25 = 0x0013, + ISDN = 0x0014, + RT = 0x0015, + NSAP = 0x0016, + NSAPPTR = 0x0017, + SIG = 0x0018, + KEY = 0x0019, + PX = 0x001a, + GPOS = 0x001b, + AAAA = 0x001c, + LOC = 0x001d, + NXT = 0x001e, + EID = 0x001f, + NIMLOC = 0x0020, + SRV = 0x0021, + ATMA = 0x0022, + NAPTR = 0x0023, + KX = 0x0024, + CERT = 0x0025, + A6 = 0x0026, + DNAME = 0x0027, + SINK = 0x0028, + OPT = 0x0029, + DS = 0x002B, + RRSIG = 0x002E, + NSEC = 0x002F, + DNSKEY = 0x0030, + DHCID = 0x0031, + UINFO = 0x0064, + UID = 0x0065, + GID = 0x0066, + UNSPEC = 0x0067, + ADDRS = 0x00f8, + TKEY = 0x00f9, + TSIG = 0x00fa, + IXFR = 0x00fb, + AXFR = 0x00fc, + MAILB = 0x00fd, + MAILA = 0x00fe, + ALL = 0x00ff, + WINS = 0xff01, + WINSR = 0xff02, + TLSA = 0x0034, + SVCB = 0x0040, + HTTPS = 0x0041, + pub const NBSTAT: TYPE = .WINSR; + pub const ANY: TYPE = .ALL; + }; + + pub const QUERY = packed struct(ULONG64) { + pub const STANDARD: QUERY = .{}; + ACCEPT_TRUNCATED_RESPONSE: bool = false, + USE_TCP_ONLY: bool = false, + NO_RECURSION: bool = false, + BYPASS_CACHE: bool = false, + NO_WIRE_QUERY: bool = false, + NO_LOCAL_NAME: bool = false, + NO_HOSTS_FILE: bool = false, + NO_NETBT: bool = false, + WIRE_ONLY: bool = false, + RETURN_MESSAGE: bool = false, + MULTICAST_ONLY: bool = false, + NO_MULTICAST: bool = false, + TREAT_AS_FQDN: bool = false, + ADDRCONFIG: bool = false, + DUAL_ADDR: bool = false, + Reserved15: u2 = 0, + MULTICAST_WAIT: bool = false, + MULTICAST_VERIFY: bool = false, + Reserved19: u1 = 0, + DONT_RESET_TTL_VALUES: bool = false, + DISABLE_IDN_ENCODING: bool = false, + Reserved22: u1 = 0, + APPEND_MULTILABEL: bool = false, + Reserved24: u34 = 0, + PARSE_ALL_RECORDS: bool = false, + Reserved59: u5 = 0, + + pub const REQUEST = extern struct { + Version: DWORD, + QueryName: PCWSTR, + QueryType: TYPE, + QueryOptions: QUERY = .STANDARD, + pDnsServerList: ?*ADDR.ARRAY = null, + InterfaceIndex: ULONG = 0, + pQueryCompletionCallback: ?*const COMPLETION_ROUTINE = null, + pQueryContext: ?*anyopaque = null, + + pub const @"3" = extern struct { + Base: REQUEST, + IsNetworkQueryRequired: BOOL = FALSE, + RequiredNetworkIndex: DWORD = 0, + cCustomServers: DWORD = 0, + pCustomServers: ?*CUSTOM_SERVER = null, + }; + }; + pub const RESULT = extern struct { + Version: ULONG, + QueryStatus: STATUS, + QueryOptions: QUERY, + pQueryRecords: ?*RECORD, + Reserved: ?*anyopaque, + }; + pub const CANCEL = extern struct { + Reserved: [32]CHAR align(8), + }; + pub const COMPLETION_ROUTINE = fn ( + pQueryContext: ?*anyopaque, + pQueryResults: *RESULT, + ) callconv(.winapi) void; + }; + pub const FREE_TYPE = enum(c_int) { Flat = 0, RecordList, ParsedMessageFields }; + pub const RECORD = extern struct { + pNext: ?*RECORD, + pName: *anyopaque, + wType: TYPE, + wDataLength: WORD, + Flags: FLAGS, + dwTtl: DWORD, + dwReserved: DWORD, + Data: extern union { A: [4]u8, AAAA: [16]u8 }, + + pub const FLAGS = packed struct(DWORD) { + Section: SECTION, + Delete: u1, + CharSet: u2, + Unused: u3, + Reserved: u24, + }; + }; + pub const SECTION = enum(u2) { Question, Answer, Authority, Additional }; +}; + // ref: km/ntddk.h pub const SYSTEM = struct { @@ -1725,6 +2590,68 @@ pub const CTL_CODE = packed struct(ULONG) { }; pub const IOCTL = struct { + pub const AFD = struct { + const CONTROL_CODE = packed struct { + Method: CTL_CODE.METHOD, + Function: u10, + DeviceType: CTL_CODE.FILE_DEVICE, + Reserved28: u4 = 0, + }; + pub const BIND: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 0, .Method = .NEITHER }); + pub const CONNECT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 1, .Method = .NEITHER }); + pub const START_LISTEN: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 2, .Method = .NEITHER }); + pub const WAIT_FOR_LISTEN: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 3, .Method = .BUFFERED }); + pub const ACCEPT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 4, .Method = .BUFFERED }); + pub const RECEIVE: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 5, .Method = .NEITHER }); + pub const RECEIVE_DATAGRAM: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 6, .Method = .NEITHER }); + pub const SEND: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 7, .Method = .NEITHER }); + pub const SEND_DATAGRAM: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 8, .Method = .NEITHER }); + pub const POLL: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 9, .Method = .BUFFERED }); + pub const PARTIAL_DISCONNECT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 10, .Method = .NEITHER }); + + pub const GET_ADDRESS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 11, .Method = .NEITHER }); + pub const QUERY_RECEIVE_INFO: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 12, .Method = .NEITHER }); + pub const QUERY_HANDLES: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 13, .Method = .NEITHER }); + pub const SET_INFORMATION: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 14, .Method = .NEITHER }); + pub const GET_CONTEXT_LENGTH: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 15, .Method = .NEITHER }); + pub const GET_CONTEXT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 16, .Method = .NEITHER }); + pub const SET_CONTEXT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 17, .Method = .NEITHER }); + + pub const SET_CONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 18, .Method = .BUFFERED }); + pub const SET_CONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 19, .Method = .BUFFERED }); + pub const SET_DISCONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 20, .Method = .BUFFERED }); + pub const SET_DISCONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 21, .Method = .BUFFERED }); + pub const GET_CONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 22, .Method = .BUFFERED }); + pub const GET_CONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 23, .Method = .BUFFERED }); + pub const GET_DISCONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 24, .Method = .BUFFERED }); + pub const GET_DISCONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 25, .Method = .BUFFERED }); + pub const SIZE_CONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 26, .Method = .BUFFERED }); + pub const SIZE_CONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 27, .Method = .BUFFERED }); + pub const SIZE_DISCONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 28, .Method = .BUFFERED }); + pub const SIZE_DISCONNECT_OPTIONS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 29, .Method = .BUFFERED }); + + pub const GET_INFORMATION: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 30, .Method = .NEITHER }); + pub const TRANSMIT_FILE: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 31, .Method = .NEITHER }); + pub const SUPER_ACCEPT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 32, .Method = .NEITHER }); + + pub const EVENT_SELECT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 33, .Method = .BUFFERED }); + pub const ENUM_NETWORK_EVENTS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 34, .Method = .BUFFERED }); + + pub const DEFER_ACCEPT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 35, .Method = .BUFFERED }); + pub const WAIT_FOR_LISTEN_LIFO: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 36, .Method = .BUFFERED }); + pub const SET_QOS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 37, .Method = .BUFFERED }); + pub const GET_QOS: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 38, .Method = .BUFFERED }); + pub const NO_OPERATION: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 39, .Method = .NEITHER }); + pub const VALIDATE_GROUP: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 40, .Method = .BUFFERED }); + pub const GET_UNACCEPTED_CONNECT_DATA: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 41, .Method = .BUFFERED }); + + pub const QUEUE_APC: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 42, .Method = .BUFFERED }); + + pub const SOCKOPT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 47, .Method = .NEITHER }); + pub const SUPER_CONNECT: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 49, .Method = .NEITHER }); + pub const RECV_MSG: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 51, .Method = .NEITHER }); + pub const RIO: CTL_CODE = @bitCast(CONTROL_CODE{ .DeviceType = .NETWORK, .Function = 70, .Method = .NEITHER }); + }; pub const CONDRV = struct { pub const READ_IO: CTL_CODE = .{ .DeviceType = .CONSOLE, .Function = 1, .Method = .OUT_DIRECT, .Access = .ANY }; pub const COMPLETE_IO: CTL_CODE = .{ .DeviceType = .CONSOLE, .Function = 2, .Method = .NEITHER, .Access = .ANY }; @@ -3306,15 +4233,6 @@ pub fn unexpectedError(err: Win32Error) UnexpectedError { return error.Unexpected; } -pub fn unexpectedWsaError(err: ws2_32.WinsockError) UnexpectedError { - return unexpectedError(@as(Win32Error, @enumFromInt(@intFromEnum(err)))); -} - -pub fn wsaErrorBug(err: ws2_32.WinsockError) UnexpectedError { - if (builtin.mode == .Debug) std.debug.panic("programmer bug caused syscall error: {t}", .{err}); - return error.Unexpected; -} - /// Call this when you made a windows NtDll call /// and you get an unexpected status. pub fn unexpectedStatus(status: NTSTATUS) UnexpectedError { @@ -3432,6 +4350,15 @@ fn STRING(comptime C: type) type { }; } + pub fn initZ(string: [:0]const C) @This() { + const len: USHORT = @intCast(@sizeOf(C) * string.len); + return .{ + .Length = len, + .MaximumLength = len + @sizeOf(C), + .Buffer = @constCast(string.ptr), + }; + } + pub fn isEmpty(string: *const @This()) bool { return string.Length == 0; } @@ -3465,19 +4392,6 @@ pub const IO_STATUS_BLOCK = extern struct { Information: ULONG_PTR, }; -pub const OVERLAPPED = extern struct { - Internal: ULONG_PTR, - InternalHigh: ULONG_PTR, - DUMMYUNIONNAME: extern union { - DUMMYSTRUCTNAME: extern struct { - Offset: DWORD, - OffsetHigh: DWORD, - }, - Pointer: ?PVOID, - }, - hEvent: ?HANDLE, -}; - pub const MAX_PATH = 260; pub const SECURITY_ATTRIBUTES = extern struct { @@ -3525,27 +4439,6 @@ pub const STARTF_USESTDHANDLES = 0x00000100; pub const THREAD_START_ROUTINE = fn (LPVOID) callconv(.winapi) DWORD; pub const USER_THREAD_START_ROUTINE = fn (LPVOID) callconv(.winapi) NTSTATUS; -pub const SYSTEM_INFO = extern struct { - anon1: extern union { - dwOemId: DWORD, - anon2: extern struct { - wProcessorArchitecture: WORD, - wReserved: WORD, - }, - }, - dwPageSize: DWORD, - lpMinimumApplicationAddress: LPVOID, - lpMaximumApplicationAddress: LPVOID, - dwActiveProcessorMask: DWORD_PTR, - dwNumberOfProcessors: DWORD, - dwProcessorType: DWORD, - dwAllocationGranularity: DWORD, - wProcessorLevel: WORD, - wProcessorRevision: WORD, -}; - -pub const HRESULT = c_long; - pub const GUID = extern struct { Data1: u32, Data2: u16, @@ -3914,14 +4807,6 @@ pub const PATH_MAX_WIDE = 32767; /// TODO: More verification of this assumption. pub const NAME_MAX = 255; -pub const FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; -pub const FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; -pub const FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; -pub const FORMAT_MESSAGE_FROM_STRING = 0x00000400; -pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; -pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; -pub const FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF; - pub const EXCEPTION_DATATYPE_MISALIGNMENT = 0x80000002; pub const EXCEPTION_ACCESS_VIOLATION = 0xc0000005; pub const EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d; diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 8f3e5e1fc3..1f6151308c 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -114,14 +114,14 @@ pub extern "ntdll" fn NtCreateFile( ShareAccess: FILE.SHARE, CreateDisposition: FILE.CREATE_DISPOSITION, CreateOptions: FILE.MODE, - EaBuffer: ?*anyopaque, + EaBuffer: ?*const anyopaque, EaLength: ULONG, ) callconv(.winapi) NTSTATUS; pub extern "ntdll" fn NtDeviceIoControlFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, IoControlCode: CTL_CODE, @@ -134,7 +134,7 @@ pub extern "ntdll" fn NtDeviceIoControlFile( pub extern "ntdll" fn NtFsControlFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, FsControlCode: CTL_CODE, @@ -147,7 +147,7 @@ pub extern "ntdll" fn NtFsControlFile( pub extern "ntdll" fn NtLockFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, ByteOffset: *const LARGE_INTEGER, @@ -169,7 +169,7 @@ pub extern "ntdll" fn NtOpenFile( pub extern "ntdll" fn NtQueryDirectoryFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, FileInformation: *anyopaque, @@ -199,7 +199,7 @@ pub extern "ntdll" fn NtQueryVolumeInformationFile( pub extern "ntdll" fn NtReadFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, Buffer: *anyopaque, @@ -222,7 +222,7 @@ pub extern "ntdll" fn NtSetInformationFile( pub extern "ntdll" fn NtWriteFile( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, Buffer: *const anyopaque, @@ -527,7 +527,7 @@ pub extern "ntdll" fn NtDelayExecution( pub extern "ntdll" fn NtNotifyChangeDirectoryFileEx( FileHandle: HANDLE, Event: ?HANDLE, - ApcRoutine: ?*const IO_APC_ROUTINE, + ApcRoutine: ?*align(2) const IO_APC_ROUTINE, ApcContext: ?*anyopaque, IoStatusBlock: *IO_STATUS_BLOCK, Buffer: *anyopaque, diff --git a/lib/std/os/windows/win32error.zig b/lib/std/os/windows/win32error.zig index 4dc826cbb9..58c6c5fdd7 100644 --- a/lib/std/os/windows/win32error.zig +++ b/lib/std/os/windows/win32error.zig @@ -2503,5 +2503,271 @@ pub const Win32Error = enum(u32) { REQUEST_PAUSED = 3050, /// Reissue the given operation as a cached IO operation. IO_REISSUE_AS_CACHED = 3950, + /// DNS server unable to interpret format. + DNS_FORMAT_ERROR = 9001, + /// DNS server failure. + DNS_SERVER_FAILURE = 9002, + /// DNS name does not exist. + DNS_NAME_ERROR = 9003, + /// DNS request not supported by name server. + DNS_NOT_IMPLEMENTED = 9004, + /// DNS operation refused. + DNS_REFUSED = 9005, + /// DNS name that ought not exist, does exist. + DNS_YXDOMAIN = 9006, + /// DNS RR set that ought not exist, does exist. + DNS_YXRRSET = 9007, + /// DNS RR set that ought to exist, does not exist. + DNS_NXRRSET = 9008, + /// DNS server not authoritative for zone. + DNS_NOTAUTH = 9009, + /// DNS name in update or prereq is not in zone. + DNS_NOTZONE = 9010, + /// DNS signature failed to verify. + DNS_BADSIG = 9016, + /// DNS bad key. + DNS_BADKEY = 9017, + /// DNS signature validity expired. + DNS_BADTIME = 9018, + /// Only the DNS server acting as the key master for the zone may perform this operation. + DNS_KEYMASTER_REQUIRED = 9101, + /// This operation is not allowed on a zone that is signed or has signing keys. + DNS_NOT_ALLOWED_ON_SIGNED_ZONE = 9102, + /// NSEC3 is not compatible with the RSA-SHA-1 algorithm. Choose a different algorithm or use NSEC. + /// + /// This value was also named DNS_INVALID_NSEC3_PARAMETERS + DNS_NSEC3_INCOMPATIBLE_WITH_RSA_SHA1 = 9103, + /// The zone does not have enough signing keys. There must be at least one key signing key (KSK) and at least one zone signing key (ZSK). + DNS_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS = 9104, + /// The specified algorithm is not supported. + DNS_UNSUPPORTED_ALGORITHM = 9105, + /// The specified key size is not supported. + DNS_INVALID_KEY_SIZE = 9106, + /// One or more of the signing keys for a zone are not accessible to the DNS server. Zone signing will not be operational until this error is resolved. + DNS_SIGNING_KEY_NOT_ACCESSIBLE = 9107, + /// The specified key storage provider does not support DPAPI++ data protection. Zone signing will not be operational until this error is resolved. + DNS_KSP_DOES_NOT_SUPPORT_PROTECTION = 9108, + /// An unexpected DPAPI++ error was encountered. Zone signing will not be operational until this error is resolved. + DNS_UNEXPECTED_DATA_PROTECTION_ERROR = 9109, + /// An unexpected crypto error was encountered. Zone signing may not be operational until this error is resolved. + DNS_UNEXPECTED_CNG_ERROR = 9110, + /// The DNS server encountered a signing key with an unknown version. Zone signing will not be operational until this error is resolved. + DNS_UNKNOWN_SIGNING_PARAMETER_VERSION = 9111, + /// The specified key service provider cannot be opened by the DNS server. + DNS_KSP_NOT_ACCESSIBLE = 9112, + /// The DNS server cannot accept any more signing keys with the specified algorithm and KSK flag value for this zone. + DNS_TOO_MANY_SKDS = 9113, + /// The specified rollover period is invalid. + DNS_INVALID_ROLLOVER_PERIOD = 9114, + /// The specified initial rollover offset is invalid. + DNS_INVALID_INITIAL_ROLLOVER_OFFSET = 9115, + /// The specified signing key is already in process of rolling over keys. + DNS_ROLLOVER_IN_PROGRESS = 9116, + /// The specified signing key does not have a standby key to revoke. + DNS_STANDBY_KEY_NOT_PRESENT = 9117, + /// This operation is not allowed on a zone signing key (ZSK). + DNS_NOT_ALLOWED_ON_ZSK = 9118, + /// This operation is not allowed on an active signing key. + DNS_NOT_ALLOWED_ON_ACTIVE_SKD = 9119, + /// The specified signing key is already queued for rollover. + DNS_ROLLOVER_ALREADY_QUEUED = 9120, + /// This operation is not allowed on an unsigned zone. + DNS_NOT_ALLOWED_ON_UNSIGNED_ZONE = 9121, + /// This operation could not be completed because the DNS server listed as the current key master for this zone is down or misconfigured. Resolve the problem on the current key master for this zone or use another DNS server to seize the key master role. + DNS_BAD_KEYMASTER = 9122, + /// The specified signature validity period is invalid. + DNS_INVALID_SIGNATURE_VALIDITY_PERIOD = 9123, + /// The specified NSEC3 iteration count is higher than allowed by the minimum key length used in the zone. + DNS_INVALID_NSEC3_ITERATION_COUNT = 9124, + /// This operation could not be completed because the DNS server has been configured with DNSSEC features disabled. Enable DNSSEC on the DNS server. + DNS_DNSSEC_IS_DISABLED = 9125, + /// This operation could not be completed because the XML stream received is empty or syntactically invalid. + DNS_INVALID_XML = 9126, + /// This operation completed, but no trust anchors were added because all of the trust anchors received were either invalid, unsupported, expired, or would not become valid in less than 30 days. + DNS_NO_VALID_TRUST_ANCHORS = 9127, + /// The specified signing key is not waiting for parental DS update. + DNS_ROLLOVER_NOT_POKEABLE = 9128, + /// Hash collision detected during NSEC3 signing. Specify a different user-provided salt, or use a randomly generated salt, and attempt to sign the zone again. + DNS_NSEC3_NAME_COLLISION = 9129, + /// NSEC is not compatible with the NSEC3-RSA-SHA-1 algorithm. Choose a different algorithm or use NSEC3. + DNS_NSEC_INCOMPATIBLE_WITH_NSEC3_RSA_SHA1 = 9130, + /// No records found for given DNS query. + DNS_NO_RECORDS = 9501, + /// Bad DNS packet. + DNS_BAD_PACKET = 9502, + /// No DNS packet. + DNS_NO_PACKET = 9503, + /// DNS error, check rcode. + DNS_RCODE = 9504, + /// Unsecured DNS packet. + DNS_UNSECURE_PACKET = 9505, + /// DNS query request is pending. + DNS_REQUEST_PENDING = 9506, + /// Invalid DNS type. + DNS_INVALID_TYPE = 9551, + /// Invalid IP address. + DNS_INVALID_IP_ADDRESS = 9552, + /// Invalid property. + DNS_INVALID_PROPERTY = 9553, + /// Try DNS operation again later. + DNS_TRY_AGAIN_LATER = 9554, + /// Record for given name and type is not unique. + DNS_NOT_UNIQUE = 9555, + /// DNS name does not comply with RFC specifications. + DNS_NON_RFC_NAME = 9556, + /// DNS name is a fully-qualified DNS name. + DNS_FQDN = 9557, + /// DNS name is dotted (multi-label). + DNS_DOTTED_NAME = 9558, + /// DNS name is a single-part name. + DNS_SINGLE_PART_NAME = 9559, + /// DNS name contains an invalid character. + DNS_INVALID_NAME_CHAR = 9560, + /// DNS name is entirely numeric. + DNS_NUMERIC_NAME = 9561, + /// The operation requested is not permitted on a DNS root server. + DNS_NOT_ALLOWED_ON_ROOT_SERVER = 9562, + /// The record could not be created because this part of the DNS namespace has been delegated to another server. + DNS_NOT_ALLOWED_UNDER_DELEGATION = 9563, + /// The DNS server could not find a set of root hints. + DNS_CANNOT_FIND_ROOT_HINTS = 9564, + /// The DNS server found root hints but they were not consistent across all adapters. + DNS_INCONSISTENT_ROOT_HINTS = 9565, + /// The specified value is too small for this parameter. + DNS_DWORD_VALUE_TOO_SMALL = 9566, + /// The specified value is too large for this parameter. + DNS_DWORD_VALUE_TOO_LARGE = 9567, + /// This operation is not allowed while the DNS server is loading zones in the background. Please try again later. + DNS_BACKGROUND_LOADING = 9568, + /// The operation requested is not permitted on against a DNS server running on a read-only DC. + DNS_NOT_ALLOWED_ON_RODC = 9569, + /// No data is allowed to exist underneath a DNAME record. + DNS_NOT_ALLOWED_UNDER_DNAME = 9570, + /// This operation requires credentials delegation. + DNS_DELEGATION_REQUIRED = 9571, + /// Name resolution policy table has been corrupted. DNS resolution will fail until it is fixed. Contact your network administrator. + DNS_INVALID_POLICY_TABLE = 9572, + /// DNS zone does not exist. + DNS_ZONE_DOES_NOT_EXIST = 9601, + /// DNS zone information not available. + DNS_NO_ZONE_INFO = 9602, + /// Invalid operation for DNS zone. + DNS_INVALID_ZONE_OPERATION = 9603, + /// Invalid DNS zone configuration. + DNS_ZONE_CONFIGURATION_ERROR = 9604, + /// DNS zone has no start of authority (SOA) record. + DNS_ZONE_HAS_NO_SOA_RECORD = 9605, + /// DNS zone has no Name Server (NS) record. + DNS_ZONE_HAS_NO_NS_RECORDS = 9606, + /// DNS zone is locked. + DNS_ZONE_LOCKED = 9607, + /// DNS zone creation failed. + DNS_ZONE_CREATION_FAILED = 9608, + /// DNS zone already exists. + DNS_ZONE_ALREADY_EXISTS = 9609, + /// DNS automatic zone already exists. + DNS_AUTOZONE_ALREADY_EXISTS = 9610, + /// Invalid DNS zone type. + DNS_INVALID_ZONE_TYPE = 9611, + /// Secondary DNS zone requires master IP address. + DNS_SECONDARY_REQUIRES_MASTER_IP = 9612, + /// DNS zone not secondary. + DNS_ZONE_NOT_SECONDARY = 9613, + /// Need secondary IP address. + DNS_NEED_SECONDARY_ADDRESSES = 9614, + /// WINS initialization failed. + DNS_WINS_INIT_FAILED = 9615, + /// Need WINS servers. + DNS_NEED_WINS_SERVERS = 9616, + /// NBTSTAT initialization call failed. + DNS_NBSTAT_INIT_FAILED = 9617, + /// Invalid delete of start of authority (SOA). + DNS_SOA_DELETE_INVALID = 9618, + /// A conditional forwarding zone already exists for that name. + DNS_FORWARDER_ALREADY_EXISTS = 9619, + /// This zone must be configured with one or more master DNS server IP addresses. + DNS_ZONE_REQUIRES_MASTER_IP = 9620, + /// The operation cannot be performed because this zone is shut down. + DNS_ZONE_IS_SHUTDOWN = 9621, + /// This operation cannot be performed because the zone is currently being signed. Please try again later. + DNS_ZONE_LOCKED_FOR_SIGNING = 9622, + /// Primary DNS zone requires datafile. + DNS_PRIMARY_REQUIRES_DATAFILE = 9651, + /// Invalid datafile name for DNS zone. + DNS_INVALID_DATAFILE_NAME = 9652, + /// Failed to open datafile for DNS zone. + DNS_DATAFILE_OPEN_FAILURE = 9653, + /// Failed to write datafile for DNS zone. + DNS_FILE_WRITEBACK_FAILED = 9654, + /// Failure while reading datafile for DNS zone. + DNS_DATAFILE_PARSING = 9655, + /// DNS record does not exist. + DNS_RECORD_DOES_NOT_EXIST = 9701, + /// DNS record format error. + DNS_RECORD_FORMAT = 9702, + /// Node creation failure in DNS. + DNS_NODE_CREATION_FAILED = 9703, + /// Unknown DNS record type. + DNS_UNKNOWN_RECORD_TYPE = 9704, + /// DNS record timed out. + DNS_RECORD_TIMED_OUT = 9705, + /// Name not in DNS zone. + DNS_NAME_NOT_IN_ZONE = 9706, + /// CNAME loop detected. + DNS_CNAME_LOOP = 9707, + /// Node is a CNAME DNS record. + DNS_NODE_IS_CNAME = 9708, + /// A CNAME record already exists for given name. + DNS_CNAME_COLLISION = 9709, + /// Record only at DNS zone root. + DNS_RECORD_ONLY_AT_ZONE_ROOT = 9710, + /// DNS record already exists. + DNS_RECORD_ALREADY_EXISTS = 9711, + /// Secondary DNS zone data error. + DNS_SECONDARY_DATA = 9712, + /// Could not create DNS cache data. + DNS_NO_CREATE_CACHE_DATA = 9713, + /// DNS name does not exist. + DNS_NAME_DOES_NOT_EXIST = 9714, + /// Could not create pointer (PTR) record. + DNS_PTR_CREATE_FAILED = 9715, + /// DNS domain was undeleted. + DNS_DOMAIN_UNDELETED = 9716, + /// The directory service is unavailable. + DNS_DS_UNAVAILABLE = 9717, + /// DNS zone already exists in the directory service. + DNS_DS_ZONE_ALREADY_EXISTS = 9718, + /// DNS server not creating or reading the boot file for the directory service integrated DNS zone. + DNS_NO_BOOTFILE_IF_DS_ZONE = 9719, + /// Node is a DNAME DNS record. + DNS_NODE_IS_DNAME = 9720, + /// A DNAME record already exists for given name. + DNS_DNAME_COLLISION = 9721, + /// An alias loop has been detected with either CNAME or DNAME records. + DNS_ALIAS_LOOP = 9722, + /// DNS AXFR (zone transfer) complete. + DNS_AXFR_COMPLETE = 9751, + /// DNS zone transfer failed. + DNS_AXFR = 9752, + /// Added local WINS server. + DNS_ADDED_LOCAL_WINS = 9753, + /// Secure update call needs to continue update request. + DNS_CONTINUE_NEEDED = 9801, + /// TCP/IP network protocol not installed. + DNS_NO_TCPIP = 9851, + /// No DNS servers configured for local system. + DNS_NO_DNS_SERVERS = 9852, + /// The specified directory partition does not exist. + DNS_DP_DOES_NOT_EXIST = 9901, + /// The specified directory partition already exists. + DNS_DP_ALREADY_EXISTS = 9902, + /// This DNS server is not enlisted in the specified directory partition. + DNS_DP_NOT_ENLISTED = 9903, + /// This DNS server is already enlisted in the specified directory partition. + DNS_DP_ALREADY_ENLISTED = 9904, + /// The directory partition is not available at this time. Please wait a few minutes and try again. + DNS_DP_NOT_AVAILABLE = 9905, + /// The operation failed because the domain naming master FSMO role could not be reached. The domain controller holding the domain naming master FSMO role is down or unable to service the request or is not running Windows Server 2003 or later. + DNS_DP_FSMO_ERROR = 9906, _, }; diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index 0abfe64ec3..303e532ccb 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -2,447 +2,15 @@ const std = @import("../../std.zig"); const assert = std.debug.assert; const windows = std.os.windows; -const OVERLAPPED = windows.OVERLAPPED; -const WORD = windows.WORD; -const DWORD = windows.DWORD; -const GUID = windows.GUID; const USHORT = windows.USHORT; -const WCHAR = windows.WCHAR; -const BOOL = windows.BOOL; -const HANDLE = windows.HANDLE; -const HWND = windows.HWND; -const INT = windows.INT; -const SHORT = windows.SHORT; -const CHAR = windows.CHAR; const LONG = windows.LONG; -const ULONG = windows.ULONG; -const LPARAM = windows.LPARAM; -const FARPROC = windows.FARPROC; - -pub const SOCKET = *opaque {}; -pub const INVALID_SOCKET = @as(SOCKET, @ptrFromInt(~@as(usize, 0))); pub const GROUP = u32; pub const ADDRESS_FAMILY = u16; -pub const WSAEVENT = HANDLE; // Microsoft use the signed c_int for this, but it should never be negative pub const socklen_t = u32; -pub const LM_HB_Extension = 128; -pub const LM_HB1_PnP = 1; -pub const LM_HB1_PDA_Palmtop = 2; -pub const LM_HB1_Computer = 4; -pub const LM_HB1_Printer = 8; -pub const LM_HB1_Modem = 16; -pub const LM_HB1_Fax = 32; -pub const LM_HB1_LANAccess = 64; -pub const LM_HB2_Telephony = 1; -pub const LM_HB2_FileServer = 2; -pub const ATMPROTO_AALUSER = 0; -pub const ATMPROTO_AAL1 = 1; -pub const ATMPROTO_AAL2 = 2; -pub const ATMPROTO_AAL34 = 3; -pub const ATMPROTO_AAL5 = 5; -pub const SAP_FIELD_ABSENT = 4294967294; -pub const SAP_FIELD_ANY = 4294967295; -pub const SAP_FIELD_ANY_AESA_SEL = 4294967290; -pub const SAP_FIELD_ANY_AESA_REST = 4294967291; -pub const ATM_E164 = 1; -pub const ATM_NSAP = 2; -pub const ATM_AESA = 2; -pub const ATM_ADDR_SIZE = 20; -pub const BLLI_L2_ISO_1745 = 1; -pub const BLLI_L2_Q921 = 2; -pub const BLLI_L2_X25L = 6; -pub const BLLI_L2_X25M = 7; -pub const BLLI_L2_ELAPB = 8; -pub const BLLI_L2_HDLC_ARM = 9; -pub const BLLI_L2_HDLC_NRM = 10; -pub const BLLI_L2_HDLC_ABM = 11; -pub const BLLI_L2_LLC = 12; -pub const BLLI_L2_X75 = 13; -pub const BLLI_L2_Q922 = 14; -pub const BLLI_L2_USER_SPECIFIED = 16; -pub const BLLI_L2_ISO_7776 = 17; -pub const BLLI_L3_X25 = 6; -pub const BLLI_L3_ISO_8208 = 7; -pub const BLLI_L3_X223 = 8; -pub const BLLI_L3_SIO_8473 = 9; -pub const BLLI_L3_T70 = 10; -pub const BLLI_L3_ISO_TR9577 = 11; -pub const BLLI_L3_USER_SPECIFIED = 16; -pub const BLLI_L3_IPI_SNAP = 128; -pub const BLLI_L3_IPI_IP = 204; -pub const BHLI_ISO = 0; -pub const BHLI_UserSpecific = 1; -pub const BHLI_HighLayerProfile = 2; -pub const BHLI_VendorSpecificAppId = 3; -pub const AAL5_MODE_MESSAGE = 1; -pub const AAL5_MODE_STREAMING = 2; -pub const AAL5_SSCS_NULL = 0; -pub const AAL5_SSCS_SSCOP_ASSURED = 1; -pub const AAL5_SSCS_SSCOP_NON_ASSURED = 2; -pub const AAL5_SSCS_FRAME_RELAY = 4; -pub const BCOB_A = 1; -pub const BCOB_C = 3; -pub const BCOB_X = 16; -pub const TT_NOIND = 0; -pub const TT_CBR = 4; -pub const TT_VBR = 8; -pub const TR_NOIND = 0; -pub const TR_END_TO_END = 1; -pub const TR_NO_END_TO_END = 2; -pub const CLIP_NOT = 0; -pub const CLIP_SUS = 32; -pub const UP_P2P = 0; -pub const UP_P2MP = 1; -pub const BLLI_L2_MODE_NORMAL = 64; -pub const BLLI_L2_MODE_EXT = 128; -pub const BLLI_L3_MODE_NORMAL = 64; -pub const BLLI_L3_MODE_EXT = 128; -pub const BLLI_L3_PACKET_16 = 4; -pub const BLLI_L3_PACKET_32 = 5; -pub const BLLI_L3_PACKET_64 = 6; -pub const BLLI_L3_PACKET_128 = 7; -pub const BLLI_L3_PACKET_256 = 8; -pub const BLLI_L3_PACKET_512 = 9; -pub const BLLI_L3_PACKET_1024 = 10; -pub const BLLI_L3_PACKET_2048 = 11; -pub const BLLI_L3_PACKET_4096 = 12; -pub const PI_ALLOWED = 0; -pub const PI_RESTRICTED = 64; -pub const PI_NUMBER_NOT_AVAILABLE = 128; -pub const SI_USER_NOT_SCREENED = 0; -pub const SI_USER_PASSED = 1; -pub const SI_USER_FAILED = 2; -pub const SI_NETWORK = 3; -pub const CAUSE_LOC_USER = 0; -pub const CAUSE_LOC_PRIVATE_LOCAL = 1; -pub const CAUSE_LOC_PUBLIC_LOCAL = 2; -pub const CAUSE_LOC_TRANSIT_NETWORK = 3; -pub const CAUSE_LOC_PUBLIC_REMOTE = 4; -pub const CAUSE_LOC_PRIVATE_REMOTE = 5; -pub const CAUSE_LOC_INTERNATIONAL_NETWORK = 7; -pub const CAUSE_LOC_BEYOND_INTERWORKING = 10; -pub const CAUSE_UNALLOCATED_NUMBER = 1; -pub const CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK = 2; -pub const CAUSE_NO_ROUTE_TO_DESTINATION = 3; -pub const CAUSE_VPI_VCI_UNACCEPTABLE = 10; -pub const CAUSE_NORMAL_CALL_CLEARING = 16; -pub const CAUSE_USER_BUSY = 17; -pub const CAUSE_NO_USER_RESPONDING = 18; -pub const CAUSE_CALL_REJECTED = 21; -pub const CAUSE_NUMBER_CHANGED = 22; -pub const CAUSE_USER_REJECTS_CLIR = 23; -pub const CAUSE_DESTINATION_OUT_OF_ORDER = 27; -pub const CAUSE_INVALID_NUMBER_FORMAT = 28; -pub const CAUSE_STATUS_ENQUIRY_RESPONSE = 30; -pub const CAUSE_NORMAL_UNSPECIFIED = 31; -pub const CAUSE_VPI_VCI_UNAVAILABLE = 35; -pub const CAUSE_NETWORK_OUT_OF_ORDER = 38; -pub const CAUSE_TEMPORARY_FAILURE = 41; -pub const CAUSE_ACCESS_INFORMAION_DISCARDED = 43; -pub const CAUSE_NO_VPI_VCI_AVAILABLE = 45; -pub const CAUSE_RESOURCE_UNAVAILABLE = 47; -pub const CAUSE_QOS_UNAVAILABLE = 49; -pub const CAUSE_USER_CELL_RATE_UNAVAILABLE = 51; -pub const CAUSE_BEARER_CAPABILITY_UNAUTHORIZED = 57; -pub const CAUSE_BEARER_CAPABILITY_UNAVAILABLE = 58; -pub const CAUSE_OPTION_UNAVAILABLE = 63; -pub const CAUSE_BEARER_CAPABILITY_UNIMPLEMENTED = 65; -pub const CAUSE_UNSUPPORTED_TRAFFIC_PARAMETERS = 73; -pub const CAUSE_INVALID_CALL_REFERENCE = 81; -pub const CAUSE_CHANNEL_NONEXISTENT = 82; -pub const CAUSE_INCOMPATIBLE_DESTINATION = 88; -pub const CAUSE_INVALID_ENDPOINT_REFERENCE = 89; -pub const CAUSE_INVALID_TRANSIT_NETWORK_SELECTION = 91; -pub const CAUSE_TOO_MANY_PENDING_ADD_PARTY = 92; -pub const CAUSE_AAL_PARAMETERS_UNSUPPORTED = 93; -pub const CAUSE_MANDATORY_IE_MISSING = 96; -pub const CAUSE_UNIMPLEMENTED_MESSAGE_TYPE = 97; -pub const CAUSE_UNIMPLEMENTED_IE = 99; -pub const CAUSE_INVALID_IE_CONTENTS = 100; -pub const CAUSE_INVALID_STATE_FOR_MESSAGE = 101; -pub const CAUSE_RECOVERY_ON_TIMEOUT = 102; -pub const CAUSE_INCORRECT_MESSAGE_LENGTH = 104; -pub const CAUSE_PROTOCOL_ERROR = 111; -pub const CAUSE_COND_UNKNOWN = 0; -pub const CAUSE_COND_PERMANENT = 1; -pub const CAUSE_COND_TRANSIENT = 2; -pub const CAUSE_REASON_USER = 0; -pub const CAUSE_REASON_IE_MISSING = 4; -pub const CAUSE_REASON_IE_INSUFFICIENT = 8; -pub const CAUSE_PU_PROVIDER = 0; -pub const CAUSE_PU_USER = 8; -pub const CAUSE_NA_NORMAL = 0; -pub const CAUSE_NA_ABNORMAL = 4; -pub const QOS_CLASS0 = 0; -pub const QOS_CLASS1 = 1; -pub const QOS_CLASS2 = 2; -pub const QOS_CLASS3 = 3; -pub const QOS_CLASS4 = 4; -pub const TNS_TYPE_NATIONAL = 64; -pub const TNS_PLAN_CARRIER_ID_CODE = 1; -pub const SIO_GET_NUMBER_OF_ATM_DEVICES = 1343619073; -pub const SIO_GET_ATM_ADDRESS = 3491102722; -pub const SIO_ASSOCIATE_PVC = 2417360899; -pub const SIO_GET_ATM_CONNECTION_ID = 1343619076; -pub const RIO_MSG_DONT_NOTIFY = 1; -pub const RIO_MSG_DEFER = 2; -pub const RIO_MSG_WAITALL = 4; -pub const RIO_MSG_COMMIT_ONLY = 8; -pub const RIO_MAX_CQ_SIZE = 134217728; -pub const RIO_CORRUPT_CQ = 4294967295; -pub const WINDOWS_AF_IRDA = 26; -pub const WCE_AF_IRDA = 22; -pub const IRDA_PROTO_SOCK_STREAM = 1; -pub const IRLMP_ENUMDEVICES = 16; -pub const IRLMP_IAS_SET = 17; -pub const IRLMP_IAS_QUERY = 18; -pub const IRLMP_SEND_PDU_LEN = 19; -pub const IRLMP_EXCLUSIVE_MODE = 20; -pub const IRLMP_IRLPT_MODE = 21; -pub const IRLMP_9WIRE_MODE = 22; -pub const IRLMP_TINYTP_MODE = 23; -pub const IRLMP_PARAMETERS = 24; -pub const IRLMP_DISCOVERY_MODE = 25; -pub const IRLMP_SHARP_MODE = 32; -pub const IAS_ATTRIB_NO_CLASS = 16; -pub const IAS_ATTRIB_NO_ATTRIB = 0; -pub const IAS_ATTRIB_INT = 1; -pub const IAS_ATTRIB_OCTETSEQ = 2; -pub const IAS_ATTRIB_STR = 3; -pub const IAS_MAX_USER_STRING = 256; -pub const IAS_MAX_OCTET_STRING = 1024; -pub const IAS_MAX_CLASSNAME = 64; -pub const IAS_MAX_ATTRIBNAME = 256; -pub const LmCharSetASCII = 0; -pub const LmCharSetISO_8859_1 = 1; -pub const LmCharSetISO_8859_2 = 2; -pub const LmCharSetISO_8859_3 = 3; -pub const LmCharSetISO_8859_4 = 4; -pub const LmCharSetISO_8859_5 = 5; -pub const LmCharSetISO_8859_6 = 6; -pub const LmCharSetISO_8859_7 = 7; -pub const LmCharSetISO_8859_8 = 8; -pub const LmCharSetISO_8859_9 = 9; -pub const LmCharSetUNICODE = 255; -pub const LM_BAUD_1200 = 1200; -pub const LM_BAUD_2400 = 2400; -pub const LM_BAUD_9600 = 9600; -pub const LM_BAUD_19200 = 19200; -pub const LM_BAUD_38400 = 38400; -pub const LM_BAUD_57600 = 57600; -pub const LM_BAUD_115200 = 115200; -pub const LM_BAUD_576K = 576000; -pub const LM_BAUD_1152K = 1152000; -pub const LM_BAUD_4M = 4000000; -pub const LM_BAUD_16M = 16000000; -pub const IPX_PTYPE = 16384; -pub const IPX_FILTERPTYPE = 16385; -pub const IPX_STOPFILTERPTYPE = 16387; -pub const IPX_DSTYPE = 16386; -pub const IPX_EXTENDED_ADDRESS = 16388; -pub const IPX_RECVHDR = 16389; -pub const IPX_MAXSIZE = 16390; -pub const IPX_ADDRESS = 16391; -pub const IPX_GETNETINFO = 16392; -pub const IPX_GETNETINFO_NORIP = 16393; -pub const IPX_SPXGETCONNECTIONSTATUS = 16395; -pub const IPX_ADDRESS_NOTIFY = 16396; -pub const IPX_MAX_ADAPTER_NUM = 16397; -pub const IPX_RERIPNETNUMBER = 16398; -pub const IPX_RECEIVE_BROADCAST = 16399; -pub const IPX_IMMEDIATESPXACK = 16400; -pub const MAX_MCAST_TTL = 255; -pub const RM_OPTIONSBASE = 1000; -pub const RM_RATE_WINDOW_SIZE = 1001; -pub const RM_SET_MESSAGE_BOUNDARY = 1002; -pub const RM_FLUSHCACHE = 1003; -pub const RM_SENDER_WINDOW_ADVANCE_METHOD = 1004; -pub const RM_SENDER_STATISTICS = 1005; -pub const RM_LATEJOIN = 1006; -pub const RM_SET_SEND_IF = 1007; -pub const RM_ADD_RECEIVE_IF = 1008; -pub const RM_DEL_RECEIVE_IF = 1009; -pub const RM_SEND_WINDOW_ADV_RATE = 1010; -pub const RM_USE_FEC = 1011; -pub const RM_SET_MCAST_TTL = 1012; -pub const RM_RECEIVER_STATISTICS = 1013; -pub const RM_HIGH_SPEED_INTRANET_OPT = 1014; -pub const SENDER_DEFAULT_RATE_KBITS_PER_SEC = 56; -pub const SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE = 15; -pub const MAX_WINDOW_INCREMENT_PERCENTAGE = 25; -pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0; -pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75; -pub const BITS_PER_BYTE = 8; -pub const LOG2_BITS_PER_BYTE = 3; - -pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}"); -pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}"); -pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}"); -pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}"); - -pub const WSAID_CONNECTEX = GUID{ - .Data1 = 0x25a207b9, - .Data2 = 0xddf3, - .Data3 = 0x4660, - .Data4 = [8]u8{ 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e }, -}; - -pub const WSAID_ACCEPTEX = GUID{ - .Data1 = 0xb5367df1, - .Data2 = 0xcbac, - .Data3 = 0x11cf, - .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 }, -}; - -pub const WSAID_GETACCEPTEXSOCKADDRS = GUID{ - .Data1 = 0xb5367df2, - .Data2 = 0xcbac, - .Data3 = 0x11cf, - .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 }, -}; - -pub const WSAID_WSARECVMSG = GUID{ - .Data1 = 0xf689d7c8, - .Data2 = 0x6f1f, - .Data3 = 0x436b, - .Data4 = [8]u8{ 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22 }, -}; - -pub const WSAID_WSAPOLL = GUID{ - .Data1 = 0x18C76F85, - .Data2 = 0xDC66, - .Data3 = 0x4964, - .Data4 = [8]u8{ 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B }, -}; - -pub const WSAID_WSASENDMSG = GUID{ - .Data1 = 0xa441e712, - .Data2 = 0x754f, - .Data3 = 0x43ca, - .Data4 = [8]u8{ 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d }, -}; - -pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0; -pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0; -pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1; -pub const SOCKET_SETTINGS_ALLOW_INSECURE = 2; -pub const SOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION = 1; -pub const SOCKET_SETTINGS_IPSEC_OPTIONAL_PEER_NAME_VERIFICATION = 2; -pub const SOCKET_SETTINGS_IPSEC_ALLOW_FIRST_INBOUND_PKT_UNENCRYPTED = 4; -pub const SOCKET_SETTINGS_IPSEC_PEER_NAME_IS_RAW_FORMAT = 8; -pub const SOCKET_QUERY_IPSEC2_ABORT_CONNECTION_ON_FIELD_CHANGE = 1; -pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_MM_SA_ID = 1; -pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_QM_SA_ID = 2; -pub const SOCKET_INFO_CONNECTION_SECURED = 1; -pub const SOCKET_INFO_CONNECTION_ENCRYPTED = 2; -pub const SOCKET_INFO_CONNECTION_IMPERSONATED = 4; -pub const IN4ADDR_LOOPBACK = 16777343; -pub const IN4ADDR_LOOPBACKPREFIX_LENGTH = 8; -pub const IN4ADDR_LINKLOCALPREFIX_LENGTH = 16; -pub const IN4ADDR_MULTICASTPREFIX_LENGTH = 4; -pub const IFF_UP = 1; -pub const IFF_BROADCAST = 2; -pub const IFF_LOOPBACK = 4; -pub const IFF_POINTTOPOINT = 8; -pub const IFF_MULTICAST = 16; -pub const IP_OPTIONS = 1; -pub const IP_HDRINCL = 2; -pub const IP_TOS = 3; -pub const IP_TTL = 4; -pub const IP_MULTICAST_IF = 9; -pub const IP_MULTICAST_TTL = 10; -pub const IP_MULTICAST_LOOP = 11; -pub const IP_ADD_MEMBERSHIP = 12; -pub const IP_DROP_MEMBERSHIP = 13; -pub const IP_DONTFRAGMENT = 14; -pub const IP_ADD_SOURCE_MEMBERSHIP = 15; -pub const IP_DROP_SOURCE_MEMBERSHIP = 16; -pub const IP_BLOCK_SOURCE = 17; -pub const IP_UNBLOCK_SOURCE = 18; -pub const IP_PKTINFO = 19; -pub const IP_HOPLIMIT = 21; -pub const IP_RECVTTL = 21; -pub const IP_RECEIVE_BROADCAST = 22; -pub const IP_RECVIF = 24; -pub const IP_RECVDSTADDR = 25; -pub const IP_IFLIST = 28; -pub const IP_ADD_IFLIST = 29; -pub const IP_DEL_IFLIST = 30; -pub const IP_UNICAST_IF = 31; -pub const IP_RTHDR = 32; -pub const IP_GET_IFLIST = 33; -pub const IP_RECVRTHDR = 38; -pub const IP_TCLASS = 39; -pub const IP_RECVTCLASS = 40; -pub const IP_RECVTOS = 40; -pub const IP_ORIGINAL_ARRIVAL_IF = 47; -pub const IP_ECN = 50; -pub const IP_PKTINFO_EX = 51; -pub const IP_WFP_REDIRECT_RECORDS = 60; -pub const IP_WFP_REDIRECT_CONTEXT = 70; -pub const IP_MTU_DISCOVER = 71; -pub const IP_MTU = 73; -pub const IP_NRT_INTERFACE = 74; -pub const IP_RECVERR = 75; -pub const IP_USER_MTU = 76; -pub const IP_UNSPECIFIED_TYPE_OF_SERVICE = -1; -pub const IN6ADDR_LINKLOCALPREFIX_LENGTH = 64; -pub const IN6ADDR_MULTICASTPREFIX_LENGTH = 8; -pub const IN6ADDR_SOLICITEDNODEMULTICASTPREFIX_LENGTH = 104; -pub const IN6ADDR_V4MAPPEDPREFIX_LENGTH = 96; -pub const IN6ADDR_6TO4PREFIX_LENGTH = 16; -pub const IN6ADDR_TEREDOPREFIX_LENGTH = 32; -pub const MCAST_JOIN_GROUP = 41; -pub const MCAST_LEAVE_GROUP = 42; -pub const MCAST_BLOCK_SOURCE = 43; -pub const MCAST_UNBLOCK_SOURCE = 44; -pub const MCAST_JOIN_SOURCE_GROUP = 45; -pub const MCAST_LEAVE_SOURCE_GROUP = 46; -pub const IPV6_HOPOPTS = 1; -pub const IPV6_HDRINCL = 2; -pub const IPV6_UNICAST_HOPS = 4; -pub const IPV6_MULTICAST_IF = 9; -pub const IPV6_MULTICAST_HOPS = 10; -pub const IPV6_MULTICAST_LOOP = 11; -pub const IPV6_ADD_MEMBERSHIP = 12; -pub const IPV6_DROP_MEMBERSHIP = 13; -pub const IPV6_DONTFRAG = 14; -pub const IPV6_PKTINFO = 19; -pub const IPV6_HOPLIMIT = 21; -pub const IPV6_PROTECTION_LEVEL = 23; -pub const IPV6_RECVIF = 24; -pub const IPV6_RECVDSTADDR = 25; -pub const IPV6_CHECKSUM = 26; -pub const IPV6_V6ONLY = 27; -pub const IPV6_IFLIST = 28; -pub const IPV6_ADD_IFLIST = 29; -pub const IPV6_DEL_IFLIST = 30; -pub const IPV6_UNICAST_IF = 31; -pub const IPV6_RTHDR = 32; -pub const IPV6_GET_IFLIST = 33; -pub const IPV6_RECVRTHDR = 38; -pub const IPV6_TCLASS = 39; -pub const IPV6_RECVTCLASS = 40; -pub const IPV6_ECN = 50; -pub const IPV6_PKTINFO_EX = 51; -pub const IPV6_WFP_REDIRECT_RECORDS = 60; -pub const IPV6_WFP_REDIRECT_CONTEXT = 70; -pub const IPV6_MTU_DISCOVER = 71; -pub const IPV6_MTU = 72; -pub const IPV6_NRT_INTERFACE = 74; -pub const IPV6_RECVERR = 75; -pub const IPV6_USER_MTU = 76; -pub const IP_UNSPECIFIED_HOP_LIMIT = -1; -pub const PROTECTION_LEVEL_UNRESTRICTED = 10; -pub const PROTECTION_LEVEL_EDGERESTRICTED = 20; -pub const PROTECTION_LEVEL_RESTRICTED = 30; -pub const INET_ADDRSTRLEN = 22; -pub const INET6_ADDRSTRLEN = 65; - pub const TCP = struct { pub const NODELAY = 1; pub const EXPEDITED_1122 = 2; @@ -469,10 +37,6 @@ pub const TCP = struct { pub const BSDURGENT = 28672; }; -pub const UDP_SEND_MSG_SIZE = 2; -pub const UDP_RECV_MAX_COALESCED_SIZE = 3; -pub const UDP_COALESCED_INFO = 3; - pub const AF = struct { pub const UNSPEC = 0; pub const UNIX = 1; @@ -507,6 +71,7 @@ pub const AF = struct { pub const TCNPROCESS = 29; pub const TCNMESSAGE = 30; pub const ICLFXBM = 31; + pub const BTH = 32; pub const LINK = 33; pub const HYPERV = 34; }; @@ -517,15 +82,6 @@ pub const SOCK = struct { pub const RAW = 3; pub const RDM = 4; pub const SEQPACKET = 5; - - /// WARNING: this flag is not supported by windows socket functions directly, - /// it is only supported by std.os.socket. Be sure that this value does - /// not share any bits with any of the `SOCK` values. - pub const CLOEXEC = 0x10000; - /// WARNING: this flag is not supported by windows socket functions directly, - /// it is only supported by std.os.socket. Be sure that this value does - /// not share any bits with any of the `SOCK` values. - pub const NONBLOCK = 0x20000; }; pub const SOL = struct { @@ -581,84 +137,9 @@ pub const SO = struct { pub const UPDATE_ACCEPT_CONTEXT = 28683; pub const CONNECT_TIME = 28684; pub const UPDATE_CONNECT_CONTEXT = 28688; -}; -pub const WSK_SO_BASE = 16384; -pub const IOC_UNIX = 0; -pub const IOC_WS2 = 134217728; -pub const IOC_PROTOCOL = 268435456; -pub const IOC_VENDOR = 402653184; -pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6; -pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27; -pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28; -pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29; -pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34; -pub const IPPORT_TCPMUX = 1; -pub const IPPORT_ECHO = 7; -pub const IPPORT_DISCARD = 9; -pub const IPPORT_SYSTAT = 11; -pub const IPPORT_DAYTIME = 13; -pub const IPPORT_NETSTAT = 15; -pub const IPPORT_QOTD = 17; -pub const IPPORT_MSP = 18; -pub const IPPORT_CHARGEN = 19; -pub const IPPORT_FTP_DATA = 20; -pub const IPPORT_FTP = 21; -pub const IPPORT_TELNET = 23; -pub const IPPORT_SMTP = 25; -pub const IPPORT_TIMESERVER = 37; -pub const IPPORT_NAMESERVER = 42; -pub const IPPORT_WHOIS = 43; -pub const IPPORT_MTP = 57; -pub const IPPORT_TFTP = 69; -pub const IPPORT_RJE = 77; -pub const IPPORT_FINGER = 79; -pub const IPPORT_TTYLINK = 87; -pub const IPPORT_SUPDUP = 95; -pub const IPPORT_POP3 = 110; -pub const IPPORT_NTP = 123; -pub const IPPORT_EPMAP = 135; -pub const IPPORT_NETBIOS_NS = 137; -pub const IPPORT_NETBIOS_DGM = 138; -pub const IPPORT_NETBIOS_SSN = 139; -pub const IPPORT_IMAP = 143; -pub const IPPORT_SNMP = 161; -pub const IPPORT_SNMP_TRAP = 162; -pub const IPPORT_IMAP3 = 220; -pub const IPPORT_LDAP = 389; -pub const IPPORT_HTTPS = 443; -pub const IPPORT_MICROSOFT_DS = 445; -pub const IPPORT_EXECSERVER = 512; -pub const IPPORT_LOGINSERVER = 513; -pub const IPPORT_CMDSERVER = 514; -pub const IPPORT_EFSSERVER = 520; -pub const IPPORT_BIFFUDP = 512; -pub const IPPORT_WHOSERVER = 513; -pub const IPPORT_ROUTESERVER = 520; -pub const IPPORT_RESERVED = 1024; -pub const IPPORT_REGISTERED_MAX = 49151; -pub const IPPORT_DYNAMIC_MIN = 49152; -pub const IPPORT_DYNAMIC_MAX = 65535; -pub const IN_CLASSA_NET = 4278190080; -pub const IN_CLASSA_NSHIFT = 24; -pub const IN_CLASSA_HOST = 16777215; -pub const IN_CLASSA_MAX = 128; -pub const IN_CLASSB_NET = 4294901760; -pub const IN_CLASSB_NSHIFT = 16; -pub const IN_CLASSB_HOST = 65535; -pub const IN_CLASSB_MAX = 65536; -pub const IN_CLASSC_NET = 4294967040; -pub const IN_CLASSC_NSHIFT = 8; -pub const IN_CLASSC_HOST = 255; -pub const IN_CLASSD_NET = 4026531840; -pub const IN_CLASSD_NSHIFT = 28; -pub const IN_CLASSD_HOST = 268435455; -pub const INADDR_LOOPBACK = 2130706433; -pub const INADDR_NONE = 4294967295; -pub const IOCPARM_MASK = 127; -pub const IOC_VOID = 536870912; -pub const IOC_OUT = 1073741824; -pub const IOC_IN = 2147483648; + pub const UNIX_PATH = 0x98000000; +}; pub const MSG = struct { pub const OOB = 0x1; @@ -678,215 +159,6 @@ pub const MSG = struct { pub const MAXIOVLEN = 16; }; -pub const AI = packed struct(u32) { - PASSIVE: bool = false, - CANONNAME: bool = false, - NUMERICHOST: bool = false, - NUMERICSERV: bool = false, - DNS_ONLY: bool = false, - _5: u3 = 0, - ALL: bool = false, - _9: u1 = 0, - ADDRCONFIG: bool = false, - V4MAPPED: bool = false, - _12: u2 = 0, - NON_AUTHORITATIVE: bool = false, - SECURE: bool = false, - RETURN_PREFERRED_NAMES: bool = false, - FQDN: bool = false, - FILESERVER: bool = false, - DISABLE_IDN_ENCODING: bool = false, - _20: u10 = 0, - RESOLUTION_HANDLE: bool = false, - EXTENDED: bool = false, -}; - -pub const FIONBIO = -2147195266; -pub const ADDRINFOEX_VERSION_2 = 2; -pub const ADDRINFOEX_VERSION_3 = 3; -pub const ADDRINFOEX_VERSION_4 = 4; - -pub const NS = enum(u32) { - ALL = 0, - SAP = 1, - NDS = 2, - PEER_BROWSE = 3, - SLP = 5, - DHCP = 6, - TCPIP_LOCAL = 10, - TCPIP_HOSTS = 11, - DNS = 12, - NETBT = 13, - WINS = 14, - NLA = 15, - NBP = 20, - MS = 30, - STDA = 31, - NTDS = 32, - EMAIL = 37, - X500 = 40, - NIS = 41, - NISPLUS = 42, - WRQ = 50, - NETDES = 60, -}; - -pub const NI_NOFQDN = 1; -pub const NI_NUMERICHOST = 2; -pub const NI_NAMEREQD = 4; -pub const NI_NUMERICSERV = 8; -pub const NI_DGRAM = 16; -pub const NI_MAXHOST = 1025; -pub const NI_MAXSERV = 32; -pub const INCL_WINSOCK_API_PROTOTYPES = 1; -pub const INCL_WINSOCK_API_TYPEDEFS = 0; -pub const FD_SETSIZE = 64; -pub const IMPLINK_IP = 155; -pub const IMPLINK_LOWEXPER = 156; -pub const IMPLINK_HIGHEXPER = 158; -pub const WSADESCRIPTION_LEN = 256; -pub const WSASYS_STATUS_LEN = 128; -pub const SOCKET_ERROR = -1; -pub const FROM_PROTOCOL_INFO = -1; -pub const PVD_CONFIG = 12289; -pub const SOMAXCONN = 2147483647; -pub const MAXGETHOSTSTRUCT = 1024; -pub const FD_READ_BIT = 0; -pub const FD_WRITE_BIT = 1; -pub const FD_OOB_BIT = 2; -pub const FD_ACCEPT_BIT = 3; -pub const FD_CONNECT_BIT = 4; -pub const FD_CLOSE_BIT = 5; -pub const FD_QOS_BIT = 6; -pub const FD_GROUP_QOS_BIT = 7; -pub const FD_ROUTING_INTERFACE_CHANGE_BIT = 8; -pub const FD_ADDRESS_LIST_CHANGE_BIT = 9; -pub const FD_MAX_EVENTS = 10; -pub const CF_ACCEPT = 0; -pub const CF_REJECT = 1; -pub const CF_DEFER = 2; -pub const SD_RECEIVE = 0; -pub const SD_SEND = 1; -pub const SD_BOTH = 2; -pub const SG_UNCONSTRAINED_GROUP = 1; -pub const SG_CONSTRAINED_GROUP = 2; -pub const MAX_PROTOCOL_CHAIN = 7; -pub const BASE_PROTOCOL = 1; -pub const LAYERED_PROTOCOL = 0; -pub const WSAPROTOCOL_LEN = 255; -pub const PFL_MULTIPLE_PROTO_ENTRIES = 1; -pub const PFL_RECOMMENDED_PROTO_ENTRY = 2; -pub const PFL_HIDDEN = 4; -pub const PFL_MATCHES_PROTOCOL_ZERO = 8; -pub const PFL_NETWORKDIRECT_PROVIDER = 16; -pub const XP1_CONNECTIONLESS = 1; -pub const XP1_GUARANTEED_DELIVERY = 2; -pub const XP1_GUARANTEED_ORDER = 4; -pub const XP1_MESSAGE_ORIENTED = 8; -pub const XP1_PSEUDO_STREAM = 16; -pub const XP1_GRACEFUL_CLOSE = 32; -pub const XP1_EXPEDITED_DATA = 64; -pub const XP1_CONNECT_DATA = 128; -pub const XP1_DISCONNECT_DATA = 256; -pub const XP1_SUPPORT_BROADCAST = 512; -pub const XP1_SUPPORT_MULTIPOINT = 1024; -pub const XP1_MULTIPOINT_CONTROL_PLANE = 2048; -pub const XP1_MULTIPOINT_DATA_PLANE = 4096; -pub const XP1_QOS_SUPPORTED = 8192; -pub const XP1_INTERRUPT = 16384; -pub const XP1_UNI_SEND = 32768; -pub const XP1_UNI_RECV = 65536; -pub const XP1_IFS_HANDLES = 131072; -pub const XP1_PARTIAL_MESSAGE = 262144; -pub const XP1_SAN_SUPPORT_SDP = 524288; -pub const BIGENDIAN = 0; -pub const LITTLEENDIAN = 1; -pub const SECURITY_PROTOCOL_NONE = 0; -pub const JL_SENDER_ONLY = 1; -pub const JL_RECEIVER_ONLY = 2; -pub const JL_BOTH = 4; -pub const WSA_FLAG_OVERLAPPED = 1; -pub const WSA_FLAG_MULTIPOINT_C_ROOT = 2; -pub const WSA_FLAG_MULTIPOINT_C_LEAF = 4; -pub const WSA_FLAG_MULTIPOINT_D_ROOT = 8; -pub const WSA_FLAG_MULTIPOINT_D_LEAF = 16; -pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 64; -pub const WSA_FLAG_NO_HANDLE_INHERIT = 128; -pub const WSA_FLAG_REGISTERED_IO = 256; -pub const TH_NETDEV = 1; -pub const TH_TAPI = 2; -pub const SERVICE_MULTIPLE = 1; -pub const NS_LOCALNAME = 19; -pub const RES_UNUSED_1 = 1; -pub const RES_FLUSH_CACHE = 2; -pub const RES_SERVICE = 4; -pub const LUP_DEEP = 1; -pub const LUP_CONTAINERS = 2; -pub const LUP_NOCONTAINERS = 4; -pub const LUP_NEAREST = 8; -pub const LUP_RETURN_NAME = 16; -pub const LUP_RETURN_TYPE = 32; -pub const LUP_RETURN_VERSION = 64; -pub const LUP_RETURN_COMMENT = 128; -pub const LUP_RETURN_ADDR = 256; -pub const LUP_RETURN_BLOB = 512; -pub const LUP_RETURN_ALIASES = 1024; -pub const LUP_RETURN_QUERY_STRING = 2048; -pub const LUP_RETURN_ALL = 4080; -pub const LUP_RES_SERVICE = 32768; -pub const LUP_FLUSHCACHE = 4096; -pub const LUP_FLUSHPREVIOUS = 8192; -pub const LUP_NON_AUTHORITATIVE = 16384; -pub const LUP_SECURE = 32768; -pub const LUP_RETURN_PREFERRED_NAMES = 65536; -pub const LUP_DNS_ONLY = 131072; -pub const LUP_ADDRCONFIG = 1048576; -pub const LUP_DUAL_ADDR = 2097152; -pub const LUP_FILESERVER = 4194304; -pub const LUP_DISABLE_IDN_ENCODING = 8388608; -pub const LUP_API_ANSI = 16777216; -pub const LUP_RESOLUTION_HANDLE = 2147483648; -pub const RESULT_IS_ALIAS = 1; -pub const RESULT_IS_ADDED = 16; -pub const RESULT_IS_CHANGED = 32; -pub const RESULT_IS_DELETED = 64; - -pub const POLL = struct { - pub const RDNORM = 256; - pub const RDBAND = 512; - pub const PRI = 1024; - pub const WRNORM = 16; - pub const WRBAND = 32; - pub const ERR = 1; - pub const HUP = 2; - pub const NVAL = 4; - pub const IN = RDNORM | RDBAND; - pub const OUT = WRNORM; -}; - -pub const TF_DISCONNECT = 1; -pub const TF_REUSE_SOCKET = 2; -pub const TF_WRITE_BEHIND = 4; -pub const TF_USE_DEFAULT_WORKER = 0; -pub const TF_USE_SYSTEM_THREAD = 16; -pub const TF_USE_KERNEL_APC = 32; -pub const TP_ELEMENT_MEMORY = 1; -pub const TP_ELEMENT_FILE = 2; -pub const TP_ELEMENT_EOP = 4; -pub const NLA_ALLUSERS_NETWORK = 1; -pub const NLA_FRIENDLY_NAME = 2; -pub const WSPDESCRIPTION_LEN = 255; -pub const WSS_OPERATION_IN_PROGRESS = 259; -pub const LSP_SYSTEM = 2147483648; -pub const LSP_INSPECTOR = 1; -pub const LSP_REDIRECTOR = 2; -pub const LSP_PROXY = 4; -pub const LSP_FIREWALL = 8; -pub const LSP_INBOUND_MODIFY = 16; -pub const LSP_OUTBOUND_MODIFY = 32; -pub const LSP_CRYPTO_COMPRESS = 64; -pub const LSP_LOCAL_CACHE = 128; - pub const IPPROTO = struct { pub const IP = 0; pub const ICMP = 1; @@ -902,77 +174,6 @@ pub const IPPROTO = struct { pub const MAX = 256; }; -pub const IP_DEFAULT_MULTICAST_TTL = 1; -pub const IP_DEFAULT_MULTICAST_LOOP = 1; -pub const IP_MAX_MEMBERSHIPS = 20; -pub const FD_READ = 1; -pub const FD_WRITE = 2; -pub const FD_OOB = 4; -pub const FD_ACCEPT = 8; -pub const FD_CONNECT = 16; -pub const FD_CLOSE = 32; -pub const SERVICE_RESOURCE = 1; -pub const SERVICE_SERVICE = 2; -pub const SERVICE_LOCAL = 4; -pub const SERVICE_FLAG_DEFER = 1; -pub const SERVICE_FLAG_HARD = 2; -pub const PROP_COMMENT = 1; -pub const PROP_LOCALE = 2; -pub const PROP_DISPLAY_HINT = 4; -pub const PROP_VERSION = 8; -pub const PROP_START_TIME = 16; -pub const PROP_MACHINE = 32; -pub const PROP_ADDRESSES = 256; -pub const PROP_SD = 512; -pub const PROP_ALL = 2147483648; -pub const SERVICE_ADDRESS_FLAG_RPC_CN = 1; -pub const SERVICE_ADDRESS_FLAG_RPC_DG = 2; -pub const SERVICE_ADDRESS_FLAG_RPC_NB = 4; -pub const NS_DEFAULT = 0; -pub const NS_VNS = 50; -pub const NSTYPE_HIERARCHICAL = 1; -pub const NSTYPE_DYNAMIC = 2; -pub const NSTYPE_ENUMERABLE = 4; -pub const NSTYPE_WORKGROUP = 8; -pub const XP_CONNECTIONLESS = 1; -pub const XP_GUARANTEED_DELIVERY = 2; -pub const XP_GUARANTEED_ORDER = 4; -pub const XP_MESSAGE_ORIENTED = 8; -pub const XP_PSEUDO_STREAM = 16; -pub const XP_GRACEFUL_CLOSE = 32; -pub const XP_EXPEDITED_DATA = 64; -pub const XP_CONNECT_DATA = 128; -pub const XP_DISCONNECT_DATA = 256; -pub const XP_SUPPORTS_BROADCAST = 512; -pub const XP_SUPPORTS_MULTICAST = 1024; -pub const XP_BANDWIDTH_ALLOCATION = 2048; -pub const XP_FRAGMENTATION = 4096; -pub const XP_ENCRYPTS = 8192; -pub const RES_SOFT_SEARCH = 1; -pub const RES_FIND_MULTIPLE = 2; -pub const SET_SERVICE_PARTIAL_SUCCESS = 1; -pub const UDP_NOCHECKSUM = 1; -pub const UDP_CHECKSUM_COVERAGE = 20; -pub const GAI_STRERROR_BUFFER_SIZE = 1024; - -pub const LPCONDITIONPROC = *const fn ( - lpCallerId: *WSABUF, - lpCallerData: *WSABUF, - lpSQOS: *QOS, - lpGQOS: *QOS, - lpCalleeId: *WSABUF, - lpCalleeData: *WSABUF, - g: *u32, - dwCallbackData: usize, -) callconv(.winapi) i32; - -pub const LPWSAOVERLAPPED_COMPLETION_ROUTINE = *const fn ( - dwError: u32, - cbTransferred: u32, - lpOverlapped: *OVERLAPPED, - dwFlags: u32, -) callconv(.winapi) void; - pub const FLOWSPEC = extern struct { TokenRate: u32, TokenBucketSize: u32, @@ -984,94 +185,6 @@ pub const FLOWSPEC = extern struct { MinimumPolicedSize: u32, }; -pub const QOS = extern struct { - SendingFlowspec: FLOWSPEC, - ReceivingFlowspec: FLOWSPEC, - ProviderSpecific: WSABUF, -}; - -pub const SOCKET_ADDRESS = extern struct { - lpSockaddr: *sockaddr, - iSockaddrLength: i32, -}; - -pub const SOCKET_ADDRESS_LIST = extern struct { - iAddressCount: i32, - Address: [1]SOCKET_ADDRESS, -}; - -pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64)) - extern struct { - wVersion: WORD, - wHighVersion: WORD, - iMaxSockets: u16, - iMaxUdpDg: u16, - lpVendorInfo: *u8, - szDescription: [WSADESCRIPTION_LEN + 1]u8, - szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, - } -else - extern struct { - wVersion: WORD, - wHighVersion: WORD, - szDescription: [WSADESCRIPTION_LEN + 1]u8, - szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, - iMaxSockets: u16, - iMaxUdpDg: u16, - lpVendorInfo: *u8, - }; - -pub const WSAPROTOCOLCHAIN = extern struct { - ChainLen: c_int, - ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD, -}; - -pub const WSAPROTOCOL_INFOA = extern struct { - dwServiceFlags1: DWORD, - dwServiceFlags2: DWORD, - dwServiceFlags3: DWORD, - dwServiceFlags4: DWORD, - dwProviderFlags: DWORD, - ProviderId: GUID, - dwCatalogEntryId: DWORD, - ProtocolChain: WSAPROTOCOLCHAIN, - iVersion: c_int, - iAddressFamily: c_int, - iMaxSockAddr: c_int, - iMinSockAddr: c_int, - iSocketType: c_int, - iProtocol: c_int, - iProtocolMaxOffset: c_int, - iNetworkByteOrder: c_int, - iSecurityScheme: c_int, - dwMessageSize: DWORD, - dwProviderReserved: DWORD, - szProtocol: [WSAPROTOCOL_LEN + 1]CHAR, -}; - -pub const WSAPROTOCOL_INFOW = extern struct { - dwServiceFlags1: DWORD, - dwServiceFlags2: DWORD, - dwServiceFlags3: DWORD, - dwServiceFlags4: DWORD, - dwProviderFlags: DWORD, - ProviderId: GUID, - dwCatalogEntryId: DWORD, - ProtocolChain: WSAPROTOCOLCHAIN, - iVersion: c_int, - iAddressFamily: c_int, - iMaxSockAddr: c_int, - iMinSockAddr: c_int, - iSocketType: c_int, - iProtocol: c_int, - iProtocolMaxOffset: c_int, - iNetworkByteOrder: c_int, - iSecurityScheme: c_int, - dwMessageSize: DWORD, - dwProviderReserved: DWORD, - szProtocol: [WSAPROTOCOL_LEN + 1]WCHAR, -}; - pub const sockproto = extern struct { sp_family: u16, sp_protocol: u16, @@ -1082,25 +195,6 @@ pub const linger = extern struct { linger: u16, }; -pub const WSANETWORKEVENTS = extern struct { - lNetworkEvents: i32, - iErrorCode: [10]i32, -}; - -pub const ADDRINFOEXW = extern struct { - flags: AI, - family: i32, - socktype: i32, - protocol: i32, - addrlen: usize, - canonname: ?[*:0]u16, - addr: ?*sockaddr, - blob: ?*anyopaque, - bloblen: usize, - provider: ?*GUID, - next: ?*ADDRINFOEXW, -}; - pub const sockaddr = extern struct { family: ADDRESS_FAMILY, data: [14]u8, @@ -1140,118 +234,6 @@ pub const sockaddr = extern struct { }; }; -pub const WSABUF = extern struct { - len: ULONG, - buf: [*]u8, -}; - -pub const msghdr = WSAMSG; -pub const msghdr_const = WSAMSG_const; - -pub const WSAMSG_const = extern struct { - name: *const sockaddr, - namelen: INT, - lpBuffers: [*]const WSABUF, - dwBufferCount: DWORD, - Control: WSABUF, - dwFlags: DWORD, -}; - -pub const WSAMSG = extern struct { - name: *sockaddr, - namelen: INT, - lpBuffers: [*]WSABUF, - dwBufferCount: DWORD, - Control: WSABUF, - dwFlags: DWORD, -}; - -pub const WSAPOLLFD = pollfd; - -pub const pollfd = extern struct { - fd: SOCKET, - events: SHORT, - revents: SHORT, -}; - -pub const TRANSMIT_FILE_BUFFERS = extern struct { - Head: *anyopaque, - HeadLength: u32, - Tail: *anyopaque, - TailLength: u32, -}; - -pub const LPFN_TRANSMITFILE = *const fn ( - hSocket: SOCKET, - hFile: HANDLE, - nNumberOfBytesToWrite: u32, - nNumberOfBytesPerSend: u32, - lpOverlapped: ?*OVERLAPPED, - lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS, - dwReserved: u32, -) callconv(.winapi) BOOL; - -pub const LPFN_ACCEPTEX = *const fn ( - sListenSocket: SOCKET, - sAcceptSocket: SOCKET, - lpOutputBuffer: *anyopaque, - dwReceiveDataLength: u32, - dwLocalAddressLength: u32, - dwRemoteAddressLength: u32, - lpdwBytesReceived: *u32, - lpOverlapped: *OVERLAPPED, -) callconv(.winapi) BOOL; - -pub const LPFN_GETACCEPTEXSOCKADDRS = *const fn ( - lpOutputBuffer: *anyopaque, - dwReceiveDataLength: u32, - dwLocalAddressLength: u32, - dwRemoteAddressLength: u32, - LocalSockaddr: **sockaddr, - LocalSockaddrLength: *i32, - RemoteSockaddr: **sockaddr, - RemoteSockaddrLength: *i32, -) callconv(.winapi) void; - -pub const LPFN_WSASENDMSG = *const fn ( - s: SOCKET, - lpMsg: *const WSAMSG_const, - dwFlags: u32, - lpNumberOfBytesSent: ?*u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub const LPFN_WSARECVMSG = *const fn ( - s: SOCKET, - lpMsg: *WSAMSG, - lpdwNumberOfBytesRecv: ?*u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub const LPSERVICE_CALLBACK_PROC = *const fn ( - lParam: LPARAM, - hAsyncTaskHandle: HANDLE, -) callconv(.winapi) void; - -pub const SERVICE_ASYNC_INFO = extern struct { - lpServiceCallbackProc: LPSERVICE_CALLBACK_PROC, - lParam: LPARAM, - hAsyncTaskHandle: HANDLE, -}; - -pub const LPLOOKUPSERVICE_COMPLETION_ROUTINE = *const fn ( - dwError: u32, - dwBytes: u32, - lpOverlapped: *OVERLAPPED, -) callconv(.winapi) void; - -pub const fd_set = extern struct { - fd_count: u32, - fd_array: [64]SOCKET, -}; - pub const hostent = extern struct { h_name: [*]u8, h_aliases: **i8, @@ -1264,904 +246,3 @@ pub const timeval = extern struct { sec: LONG, usec: LONG, }; - -/// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2 -pub const WinsockError = enum(u16) { - /// Specified event object handle is invalid. - /// An application attempts to use an event object, but the specified handle is not valid. - INVALID_HANDLE = 6, - /// Insufficient memory available. - /// An application used a Windows Sockets function that directly maps to a Windows function. - /// The Windows function is indicating a lack of required memory resources. - NOT_ENOUGH_MEMORY = 8, - /// One or more parameters are invalid. - /// An application used a Windows Sockets function which directly maps to a Windows function. - /// The Windows function is indicating a problem with one or more parameters. - INVALID_PARAMETER = 87, - /// Overlapped operation aborted. - /// An overlapped operation was canceled due to the closure of the socket, or the execution of the SIO_FLUSH command in WSAIoctl. - OPERATION_ABORTED = 995, - /// Overlapped I/O event object not in signaled state. - /// The application has tried to determine the status of an overlapped operation which is not yet completed. - /// Applications that use WSAGetOverlappedResult (with the fWait flag set to FALSE) in a polling mode to determine when an overlapped operation has completed, get this error code until the operation is complete. - IO_INCOMPLETE = 996, - /// The application has initiated an overlapped operation that cannot be completed immediately. - /// A completion indication will be given later when the operation has been completed. - IO_PENDING = 997, - /// Interrupted function call. - /// A blocking operation was interrupted by a call to WSACancelBlockingCall. - EINTR = 10004, - /// File handle is not valid. - /// The file handle supplied is not valid. - EBADF = 10009, - /// Permission denied. - /// An attempt was made to access a socket in a way forbidden by its access permissions. - /// An example is using a broadcast address for sendto without broadcast permission being set using setsockopt(SO.BROADCAST). - /// Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4.0 with SP4 and later), another application, service, or kernel mode driver is bound to the same address with exclusive access. - /// Such exclusive access is a new feature of Windows NT 4.0 with SP4 and later, and is implemented by using the SO.EXCLUSIVEADDRUSE option. - EACCES = 10013, - /// Bad address. - /// The system detected an invalid pointer address in attempting to use a pointer argument of a call. - /// This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. - /// For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr). - EFAULT = 10014, - /// Invalid argument. - /// Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). - /// In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening. - EINVAL = 10022, - /// Too many open files. - /// Too many open sockets. Each implementation may have a maximum number of socket handles available, either globally, per process, or per thread. - EMFILE = 10024, - /// Resource temporarily unavailable. - /// This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. - /// It is a nonfatal error, and the operation should be retried later. - /// It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect on a nonblocking SOCK.STREAM socket, since some time must elapse for the connection to be established. - EWOULDBLOCK = 10035, - /// Operation now in progress. - /// A blocking operation is currently executing. - /// Windows Sockets only allows a single blocking operation—per- task or thread—to be outstanding, and if any other function call is made (whether or not it references that or any other socket) the function fails with the WSAEINPROGRESS error. - EINPROGRESS = 10036, - /// Operation already in progress. - /// An operation was attempted on a nonblocking socket with an operation already in progress—that is, calling connect a second time on a nonblocking socket that is already connecting, or canceling an asynchronous request (WSAAsyncGetXbyY) that has already been canceled or completed. - EALREADY = 10037, - /// Socket operation on nonsocket. - /// An operation was attempted on something that is not a socket. - /// Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid. - ENOTSOCK = 10038, - /// Destination address required. - /// A required address was omitted from an operation on a socket. - /// For example, this error is returned if sendto is called with the remote address of ADDR_ANY. - EDESTADDRREQ = 10039, - /// Message too long. - /// A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram was smaller than the datagram itself. - EMSGSIZE = 10040, - /// Protocol wrong type for socket. - /// A protocol was specified in the socket function call that does not support the semantics of the socket type requested. - /// For example, the ARPA Internet UDP protocol cannot be specified with a socket type of SOCK.STREAM. - EPROTOTYPE = 10041, - /// Bad protocol option. - /// An unknown, invalid or unsupported option or level was specified in a getsockopt or setsockopt call. - ENOPROTOOPT = 10042, - /// Protocol not supported. - /// The requested protocol has not been configured into the system, or no implementation for it exists. - /// For example, a socket call requests a SOCK.DGRAM socket, but specifies a stream protocol. - EPROTONOSUPPORT = 10043, - /// Socket type not supported. - /// The support for the specified socket type does not exist in this address family. - /// For example, the optional type SOCK.RAW might be selected in a socket call, and the implementation does not support SOCK.RAW sockets at all. - ESOCKTNOSUPPORT = 10044, - /// Operation not supported. - /// The attempted operation is not supported for the type of object referenced. - /// Usually this occurs when a socket descriptor to a socket that cannot support this operation is trying to accept a connection on a datagram socket. - EOPNOTSUPP = 10045, - /// Protocol family not supported. - /// The protocol family has not been configured into the system or no implementation for it exists. - /// This message has a slightly different meaning from WSAEAFNOSUPPORT. - /// However, it is interchangeable in most cases, and all Windows Sockets functions that return one of these messages also specify WSAEAFNOSUPPORT. - EPFNOSUPPORT = 10046, - /// Address family not supported by protocol family. - /// An address incompatible with the requested protocol was used. - /// All sockets are created with an associated address family (that is, AF.INET for Internet Protocols) and a generic protocol type (that is, SOCK.STREAM). - /// This error is returned if an incorrect protocol is explicitly requested in the socket call, or if an address of the wrong family is used for a socket, for example, in sendto. - EAFNOSUPPORT = 10047, - /// Address already in use. - /// Typically, only one usage of each socket address (protocol/IP address/port) is permitted. - /// This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that was not closed properly, or one that is still in the process of closing. - /// For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO.REUSEADDR). - /// Client applications usually need not call bind at all—connect chooses an unused port automatically. - /// When bind is called with a wildcard address (involving ADDR_ANY), a WSAEADDRINUSE error could be delayed until the specific address is committed. - /// This could happen with a call to another function later, including connect, listen, WSAConnect, or WSAJoinLeaf. - EADDRINUSE = 10048, - /// Cannot assign requested address. - /// The requested address is not valid in its context. - /// This normally results from an attempt to bind to an address that is not valid for the local computer. - /// This can also result from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the remote address or port is not valid for a remote computer (for example, address or port 0). - EADDRNOTAVAIL = 10049, - /// Network is down. - /// A socket operation encountered a dead network. - /// This could indicate a serious failure of the network system (that is, the protocol stack that the Windows Sockets DLL runs over), the network interface, or the local network itself. - ENETDOWN = 10050, - /// Network is unreachable. - /// A socket operation was attempted to an unreachable network. - /// This usually means the local software knows no route to reach the remote host. - ENETUNREACH = 10051, - /// Network dropped connection on reset. - /// The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress. - /// It can also be returned by setsockopt if an attempt is made to set SO.KEEPALIVE on a connection that has already failed. - ENETRESET = 10052, - /// Software caused connection abort. - /// An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error. - ECONNABORTED = 10053, - /// Connection reset by peer. - /// An existing connection was forcibly closed by the remote host. - /// This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO.LINGER option on the remote socket). - /// This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. - /// Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET. - ECONNRESET = 10054, - /// No buffer space available. - /// An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. - ENOBUFS = 10055, - /// Socket is already connected. - /// A connect request was made on an already-connected socket. - /// Some implementations also return this error if sendto is called on a connected SOCK.DGRAM socket (for SOCK.STREAM sockets, the to parameter in sendto is ignored) although other implementations treat this as a legal occurrence. - EISCONN = 10056, - /// Socket is not connected. - /// A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied. - /// Any other type of operation might also return this error—for example, setsockopt setting SO.KEEPALIVE if the connection has been reset. - ENOTCONN = 10057, - /// Cannot send after socket shutdown. - /// A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call. - /// By calling shutdown a partial close of a socket is requested, which is a signal that sending or receiving, or both have been discontinued. - ESHUTDOWN = 10058, - /// Too many references. - /// Too many references to some kernel object. - ETOOMANYREFS = 10059, - /// Connection timed out. - /// A connection attempt failed because the connected party did not properly respond after a period of time, or the established connection failed because the connected host has failed to respond. - ETIMEDOUT = 10060, - /// Connection refused. - /// No connection could be made because the target computer actively refused it. - /// This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running. - ECONNREFUSED = 10061, - /// Cannot translate name. - /// Cannot translate a name. - ELOOP = 10062, - /// Name too long. - /// A name component or a name was too long. - ENAMETOOLONG = 10063, - /// Host is down. - /// A socket operation failed because the destination host is down. A socket operation encountered a dead host. - /// Networking activity on the local host has not been initiated. - /// These conditions are more likely to be indicated by the error WSAETIMEDOUT. - EHOSTDOWN = 10064, - /// No route to host. - /// A socket operation was attempted to an unreachable host. See WSAENETUNREACH. - EHOSTUNREACH = 10065, - /// Directory not empty. - /// Cannot remove a directory that is not empty. - ENOTEMPTY = 10066, - /// Too many processes. - /// A Windows Sockets implementation may have a limit on the number of applications that can use it simultaneously. - /// WSAStartup may fail with this error if the limit has been reached. - EPROCLIM = 10067, - /// User quota exceeded. - /// Ran out of user quota. - EUSERS = 10068, - /// Disk quota exceeded. - /// Ran out of disk quota. - EDQUOT = 10069, - /// Stale file handle reference. - /// The file handle reference is no longer available. - ESTALE = 10070, - /// Item is remote. - /// The item is not available locally. - EREMOTE = 10071, - /// Network subsystem is unavailable. - /// This error is returned by WSAStartup if the Windows Sockets implementation cannot function at this time because the underlying system it uses to provide network services is currently unavailable. - /// Users should check: - /// - That the appropriate Windows Sockets DLL file is in the current path. - /// - That they are not trying to use more than one Windows Sockets implementation simultaneously. - /// - If there is more than one Winsock DLL on your system, be sure the first one in the path is appropriate for the network subsystem currently loaded. - /// - The Windows Sockets implementation documentation to be sure all necessary components are currently installed and configured correctly. - SYSNOTREADY = 10091, - /// Winsock.dll version out of range. - /// The current Windows Sockets implementation does not support the Windows Sockets specification version requested by the application. - /// Check that no old Windows Sockets DLL files are being accessed. - VERNOTSUPPORTED = 10092, - /// Successful WSAStartup not yet performed. - /// Either the application has not called WSAStartup or WSAStartup failed. - /// The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks), or WSACleanup has been called too many times. - NOTINITIALISED = 10093, - /// Graceful shutdown in progress. - /// Returned by WSARecv and WSARecvFrom to indicate that the remote party has initiated a graceful shutdown sequence. - EDISCON = 10101, - /// No more results. - /// No more results can be returned by the WSALookupServiceNext function. - ENOMORE = 10102, - /// Call has been canceled. - /// A call to the WSALookupServiceEnd function was made while this call was still processing. The call has been canceled. - ECANCELLED = 10103, - /// Procedure call table is invalid. - /// The service provider procedure call table is invalid. - /// A service provider returned a bogus procedure table to Ws2_32.dll. - /// This is usually caused by one or more of the function pointers being NULL. - EINVALIDPROCTABLE = 10104, - /// Service provider is invalid. - /// The requested service provider is invalid. - /// This error is returned by the WSCGetProviderInfo and WSCGetProviderInfo32 functions if the protocol entry specified could not be found. - /// This error is also returned if the service provider returned a version number other than 2.0. - EINVALIDPROVIDER = 10105, - /// Service provider failed to initialize. - /// The requested service provider could not be loaded or initialized. - /// This error is returned if either a service provider's DLL could not be loaded (LoadLibrary failed) or the provider's WSPStartup or NSPStartup function failed. - EPROVIDERFAILEDINIT = 10106, - /// System call failure. - /// A system call that should never fail has failed. - /// This is a generic error code, returned under various conditions. - /// Returned when a system call that should never fail does fail. - /// For example, if a call to WaitForMultipleEvents fails or one of the registry functions fails trying to manipulate the protocol/namespace catalogs. - /// Returned when a provider does not return SUCCESS and does not provide an extended error code. - /// Can indicate a service provider implementation error. - SYSCALLFAILURE = 10107, - /// Service not found. - /// No such service is known. The service cannot be found in the specified name space. - SERVICE_NOT_FOUND = 10108, - /// Class type not found. - /// The specified class was not found. - TYPE_NOT_FOUND = 10109, - /// No more results. - /// No more results can be returned by the WSALookupServiceNext function. - E_NO_MORE = 10110, - /// Call was canceled. - /// A call to the WSALookupServiceEnd function was made while this call was still processing. The call has been canceled. - E_CANCELLED = 10111, - /// Database query was refused. - /// A database query failed because it was actively refused. - EREFUSED = 10112, - /// Host not found. - /// No such host is known. The name is not an official host name or alias, or it cannot be found in the database(s) being queried. - /// This error may also be returned for protocol and service queries, and means that the specified name could not be found in the relevant database. - HOST_NOT_FOUND = 11001, - /// Nonauthoritative host not found. - /// This is usually a temporary error during host name resolution and means that the local server did not receive a response from an authoritative server. A retry at some time later may be successful. - TRY_AGAIN = 11002, - /// This is a nonrecoverable error. - /// This indicates that some sort of nonrecoverable error occurred during a database lookup. - /// This may be because the database files (for example, BSD-compatible HOSTS, SERVICES, or PROTOCOLS files) could not be found, or a DNS request was returned by the server with a severe error. - NO_RECOVERY = 11003, - /// Valid name, no data record of requested type. - /// The requested name is valid and was found in the database, but it does not have the correct associated data being resolved for. - /// The usual example for this is a host name-to-address translation attempt (using gethostbyname or WSAAsyncGetHostByName) which uses the DNS (Domain Name Server). - /// An MX record is returned but no A record—indicating the host itself exists, but is not directly reachable. - NO_DATA = 11004, - /// QoS receivers. - /// At least one QoS reserve has arrived. - QOS_RECEIVERS = 11005, - /// QoS senders. - /// At least one QoS send path has arrived. - QOS_SENDERS = 11006, - /// No QoS senders. - /// There are no QoS senders. - QOS_NO_SENDERS = 11007, - /// QoS no receivers. - /// There are no QoS receivers. - QOS_NO_RECEIVERS = 11008, - /// QoS request confirmed. - /// The QoS reserve request has been confirmed. - QOS_REQUEST_CONFIRMED = 11009, - /// QoS admission error. - /// A QoS error occurred due to lack of resources. - QOS_ADMISSION_FAILURE = 11010, - /// QoS policy failure. - /// The QoS request was rejected because the policy system couldn't allocate the requested resource within the existing policy. - QOS_POLICY_FAILURE = 11011, - /// QoS bad style. - /// An unknown or conflicting QoS style was encountered. - QOS_BAD_STYLE = 11012, - /// QoS bad object. - /// A problem was encountered with some part of the filterspec or the provider-specific buffer in general. - QOS_BAD_OBJECT = 11013, - /// QoS traffic control error. - /// An error with the underlying traffic control (TC) API as the generic QoS request was converted for local enforcement by the TC API. - /// This could be due to an out of memory error or to an internal QoS provider error. - QOS_TRAFFIC_CTRL_ERROR = 11014, - /// QoS generic error. - /// A general QoS error. - QOS_GENERIC_ERROR = 11015, - /// QoS service type error. - /// An invalid or unrecognized service type was found in the QoS flowspec. - QOS_ESERVICETYPE = 11016, - /// QoS flowspec error. - /// An invalid or inconsistent flowspec was found in the QOS structure. - QOS_EFLOWSPEC = 11017, - /// Invalid QoS provider buffer. - /// An invalid QoS provider-specific buffer. - QOS_EPROVSPECBUF = 11018, - /// Invalid QoS filter style. - /// An invalid QoS filter style was used. - QOS_EFILTERSTYLE = 11019, - /// Invalid QoS filter type. - /// An invalid QoS filter type was used. - QOS_EFILTERTYPE = 11020, - /// Incorrect QoS filter count. - /// An incorrect number of QoS FILTERSPECs were specified in the FLOWDESCRIPTOR. - QOS_EFILTERCOUNT = 11021, - /// Invalid QoS object length. - /// An object with an invalid ObjectLength field was specified in the QoS provider-specific buffer. - QOS_EOBJLENGTH = 11022, - /// Incorrect QoS flow count. - /// An incorrect number of flow descriptors was specified in the QoS structure. - QOS_EFLOWCOUNT = 11023, - /// Unrecognized QoS object. - /// An unrecognized object was found in the QoS provider-specific buffer. - QOS_EUNKOWNPSOBJ = 11024, - /// Invalid QoS policy object. - /// An invalid policy object was found in the QoS provider-specific buffer. - QOS_EPOLICYOBJ = 11025, - /// Invalid QoS flow descriptor. - /// An invalid QoS flow descriptor was found in the flow descriptor list. - QOS_EFLOWDESC = 11026, - /// Invalid QoS provider-specific flowspec. - /// An invalid or inconsistent flowspec was found in the QoS provider-specific buffer. - QOS_EPSFLOWSPEC = 11027, - /// Invalid QoS provider-specific filterspec. - /// An invalid FILTERSPEC was found in the QoS provider-specific buffer. - QOS_EPSFILTERSPEC = 11028, - /// Invalid QoS shape discard mode object. - /// An invalid shape discard mode object was found in the QoS provider-specific buffer. - QOS_ESDMODEOBJ = 11029, - /// Invalid QoS shaping rate object. - /// An invalid shaping rate object was found in the QoS provider-specific buffer. - QOS_ESHAPERATEOBJ = 11030, - /// Reserved policy QoS element type. - /// A reserved policy element was found in the QoS provider-specific buffer. - QOS_RESERVED_PETYPE = 11031, - _, -}; - -pub extern "ws2_32" fn accept( - s: SOCKET, - addr: ?*sockaddr, - addrlen: ?*i32, -) callconv(.winapi) SOCKET; - -pub extern "ws2_32" fn bind( - s: SOCKET, - name: *const sockaddr, - namelen: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn closesocket( - s: SOCKET, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn connect( - s: SOCKET, - name: *const sockaddr, - namelen: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn ioctlsocket( - s: SOCKET, - cmd: i32, - argp: *u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn getpeername( - s: SOCKET, - name: *sockaddr, - namelen: *i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn getsockname( - s: SOCKET, - name: *sockaddr, - namelen: *i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn getsockopt( - s: SOCKET, - level: i32, - optname: i32, - optval: [*]u8, - optlen: *i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn htonl( - hostlong: u32, -) callconv(.winapi) u32; - -pub extern "ws2_32" fn htons( - hostshort: u16, -) callconv(.winapi) u16; - -pub extern "ws2_32" fn inet_addr( - cp: ?[*]const u8, -) callconv(.winapi) u32; - -pub extern "ws2_32" fn listen( - s: SOCKET, - backlog: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn ntohl( - netlong: u32, -) callconv(.winapi) u32; - -pub extern "ws2_32" fn ntohs( - netshort: u16, -) callconv(.winapi) u16; - -pub extern "ws2_32" fn recv( - s: SOCKET, - buf: [*]u8, - len: i32, - flags: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn recvfrom( - s: SOCKET, - buf: [*]u8, - len: i32, - flags: i32, - from: ?*sockaddr, - fromlen: ?*i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn select( - nfds: i32, - readfds: ?*fd_set, - writefds: ?*fd_set, - exceptfds: ?*fd_set, - timeout: ?*const timeval, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn send( - s: SOCKET, - buf: [*]const u8, - len: i32, - flags: u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn sendto( - s: SOCKET, - buf: [*]const u8, - len: i32, - flags: i32, - to: ?*const sockaddr, - tolen: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn setsockopt( - s: SOCKET, - level: i32, - optname: i32, - optval: ?[*]const u8, - optlen: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn shutdown( - s: SOCKET, - how: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn socket( - af: i32, - @"type": i32, - protocol: i32, -) callconv(.winapi) SOCKET; - -pub extern "ws2_32" fn WSAStartup( - wVersionRequired: WORD, - lpWSAData: *WSADATA, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSACleanup() callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASetLastError(iError: i32) callconv(.winapi) void; - -pub extern "ws2_32" fn WSAGetLastError() callconv(.winapi) WinsockError; - -pub extern "ws2_32" fn WSAIsBlocking() callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSAUnhookBlockingHook() callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASetBlockingHook(lpBlockFunc: FARPROC) callconv(.winapi) FARPROC; - -pub extern "ws2_32" fn WSACancelBlockingCall() callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAAsyncGetServByName( - hWnd: HWND, - wMsg: u32, - name: [*:0]const u8, - proto: ?[*:0]const u8, - buf: [*]u8, - buflen: i32, -) callconv(.winapi) HANDLE; - -pub extern "ws2_32" fn WSAAsyncGetServByPort( - hWnd: HWND, - wMsg: u32, - port: i32, - proto: ?[*:0]const u8, - buf: [*]u8, - buflen: i32, -) callconv(.winapi) HANDLE; - -pub extern "ws2_32" fn WSAAsyncGetProtoByName( - hWnd: HWND, - wMsg: u32, - name: [*:0]const u8, - buf: [*]u8, - buflen: i32, -) callconv(.winapi) HANDLE; - -pub extern "ws2_32" fn WSAAsyncGetProtoByNumber( - hWnd: HWND, - wMsg: u32, - number: i32, - buf: [*]u8, - buflen: i32, -) callconv(.winapi) HANDLE; - -pub extern "ws2_32" fn WSACancelAsyncRequest(hAsyncTaskHandle: HANDLE) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAAsyncSelect( - s: SOCKET, - hWnd: HWND, - wMsg: u32, - lEvent: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAAccept( - s: SOCKET, - addr: ?*sockaddr, - addrlen: ?*i32, - lpfnCondition: ?LPCONDITIONPROC, - dwCallbackData: usize, -) callconv(.winapi) SOCKET; - -pub extern "ws2_32" fn WSACloseEvent(hEvent: HANDLE) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSAConnect( - s: SOCKET, - name: *const sockaddr, - namelen: i32, - lpCallerData: ?*WSABUF, - lpCalleeData: ?*WSABUF, - lpSQOS: ?*QOS, - lpGQOS: ?*QOS, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAConnectByNameW( - s: SOCKET, - nodename: [*:0]const u16, - servicename: [*:0]const u16, - LocalAddressLength: ?*u32, - LocalAddress: ?*sockaddr, - RemoteAddressLength: ?*u32, - RemoteAddress: ?*sockaddr, - timeout: ?*const timeval, - Reserved: *OVERLAPPED, -) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSAConnectByList( - s: SOCKET, - SocketAddress: *SOCKET_ADDRESS_LIST, - LocalAddressLength: ?*u32, - LocalAddress: ?*sockaddr, - RemoteAddressLength: ?*u32, - RemoteAddress: ?*sockaddr, - timeout: ?*const timeval, - Reserved: *OVERLAPPED, -) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSACreateEvent() callconv(.winapi) HANDLE; - -pub extern "ws2_32" fn WSADuplicateSocketW( - s: SOCKET, - dwProcessId: u32, - lpProtocolInfo: *WSAPROTOCOL_INFOW, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAEnumNetworkEvents( - s: SOCKET, - hEventObject: HANDLE, - lpNetworkEvents: *WSANETWORKEVENTS, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAEnumProtocolsW( - lpiProtocols: ?*i32, - lpProtocolBuffer: ?*WSAPROTOCOL_INFOW, - lpdwBufferLength: *u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAEventSelect( - s: SOCKET, - hEventObject: HANDLE, - lNetworkEvents: i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAGetOverlappedResult( - s: SOCKET, - lpOverlapped: *OVERLAPPED, - lpcbTransfer: *u32, - fWait: BOOL, - lpdwFlags: *u32, -) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSAGetQOSByName( - s: SOCKET, - lpQOSName: *WSABUF, - lpQOS: *QOS, -) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSAHtonl( - s: SOCKET, - hostlong: u32, - lpnetlong: *u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAHtons( - s: SOCKET, - hostshort: u16, - lpnetshort: *u16, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAIoctl( - s: SOCKET, - dwIoControlCode: u32, - lpvInBuffer: ?*const anyopaque, - cbInBuffer: u32, - lpvOutbuffer: ?*anyopaque, - cbOutbuffer: u32, - lpcbBytesReturned: *u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAJoinLeaf( - s: SOCKET, - name: *const sockaddr, - namelen: i32, - lpCallerdata: ?*WSABUF, - lpCalleeData: ?*WSABUF, - lpSQOS: ?*QOS, - lpGQOS: ?*QOS, - dwFlags: u32, -) callconv(.winapi) SOCKET; - -pub extern "ws2_32" fn WSANtohl( - s: SOCKET, - netlong: u32, - lphostlong: *u32, -) callconv(.winapi) u32; - -pub extern "ws2_32" fn WSANtohs( - s: SOCKET, - netshort: u16, - lphostshort: *u16, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSARecv( - s: SOCKET, - lpBuffers: [*]WSABUF, - dwBufferCouynt: u32, - lpNumberOfBytesRecv: ?*u32, - lpFlags: *u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSARecvDisconnect( - s: SOCKET, - lpInboundDisconnectData: ?*WSABUF, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSARecvFrom( - s: SOCKET, - lpBuffers: [*]WSABUF, - dwBuffercount: u32, - lpNumberOfBytesRecvd: ?*u32, - lpFlags: *u32, - lpFrom: ?*sockaddr, - lpFromlen: ?*i32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAResetEvent(hEvent: HANDLE) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASend( - s: SOCKET, - lpBuffers: [*]WSABUF, - dwBufferCount: u32, - lpNumberOfBytesSent: ?*u32, - dwFlags: u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASendMsg( - s: SOCKET, - lpMsg: *WSAMSG_const, - dwFlags: u32, - lpNumberOfBytesSent: ?*u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASendDisconnect( - s: SOCKET, - lpOutboundDisconnectData: ?*WSABUF, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASendTo( - s: SOCKET, - lpBuffers: [*]WSABUF, - dwBufferCount: u32, - lpNumberOfBytesSent: ?*u32, - dwFlags: u32, - lpTo: ?*const sockaddr, - iToLen: i32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRounte: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSASetEvent( - hEvent: HANDLE, -) callconv(.winapi) BOOL; - -pub extern "ws2_32" fn WSASocketW( - af: i32, - @"type": i32, - protocol: i32, - lpProtocolInfo: ?*WSAPROTOCOL_INFOW, - g: u32, - dwFlags: u32, -) callconv(.winapi) SOCKET; - -pub extern "ws2_32" fn WSAWaitForMultipleEvents( - cEvents: u32, - lphEvents: [*]const HANDLE, - fWaitAll: BOOL, - dwTimeout: u32, - fAlertable: BOOL, -) callconv(.winapi) u32; - -pub extern "ws2_32" fn WSAAddressToStringW( - lpsaAddress: *sockaddr, - dwAddressLength: u32, - lpProtocolInfo: ?*WSAPROTOCOL_INFOW, - lpszAddressString: [*]u16, - lpdwAddressStringLength: *u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAStringToAddressW( - AddressString: [*:0]const u16, - AddressFamily: i32, - lpProtocolInfo: ?*WSAPROTOCOL_INFOW, - lpAddrses: *sockaddr, - lpAddressLength: *i32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAProviderConfigChange( - lpNotificationHandle: *HANDLE, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn WSAPoll( - fdArray: [*]WSAPOLLFD, - fds: u32, - timeout: i32, -) callconv(.winapi) i32; - -pub extern "mswsock" fn WSARecvEx( - s: SOCKET, - buf: [*]u8, - len: i32, - flags: *i32, -) callconv(.winapi) i32; - -pub extern "mswsock" fn TransmitFile( - hSocket: SOCKET, - hFile: HANDLE, - nNumberOfBytesToWrite: u32, - nNumberOfBytesPerSend: u32, - lpOverlapped: ?*OVERLAPPED, - lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS, - dwReserved: u32, -) callconv(.winapi) BOOL; - -pub extern "mswsock" fn AcceptEx( - sListenSocket: SOCKET, - sAcceptSocket: SOCKET, - lpOutputBuffer: *anyopaque, - dwReceiveDataLength: u32, - dwLocalAddressLength: u32, - dwRemoteAddressLength: u32, - lpdwBytesReceived: *u32, - lpOverlapped: *OVERLAPPED, -) callconv(.winapi) BOOL; - -pub extern "mswsock" fn GetAcceptExSockaddrs( - lpOutputBuffer: *anyopaque, - dwReceiveDataLength: u32, - dwLocalAddressLength: u32, - dwRemoteAddressLength: u32, - LocalSockaddr: **sockaddr, - LocalSockaddrLength: *i32, - RemoteSockaddr: **sockaddr, - RemoteSockaddrLength: *i32, -) callconv(.winapi) void; - -pub extern "ws2_32" fn WSAProviderCompleteAsyncCall( - hAsyncCall: HANDLE, - iRetCode: i32, -) callconv(.winapi) i32; - -pub extern "mswsock" fn EnumProtocolsW( - lpiProtocols: ?*i32, - lpProtocolBuffer: *anyopaque, - lpdwBufferLength: *u32, -) callconv(.winapi) i32; - -pub extern "mswsock" fn GetAddressByNameW( - dwNameSpace: NS, - lpServiceType: *GUID, - lpServiceName: ?[*:0]u16, - lpiProtocols: ?*i32, - dwResolution: u32, - lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO, - lpCsaddrBuffer: *anyopaque, - ldwBufferLEngth: *u32, - lpAliasBuffer: ?[*:0]u16, - lpdwAliasBufferLength: *u32, -) callconv(.winapi) i32; - -pub extern "mswsock" fn GetTypeByNameW( - lpServiceName: [*:0]u16, - lpServiceType: *GUID, -) callconv(.winapi) i32; - -pub extern "mswsock" fn GetNameByTypeW( - lpServiceType: *GUID, - lpServiceName: [*:0]u16, - dwNameLength: u32, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn GetAddrInfoExW( - pName: ?[*:0]const u16, - pServiceName: ?[*:0]const u16, - dwNameSpace: NS, - lpNspId: ?*GUID, - hints: ?*const ADDRINFOEXW, - ppResult: **ADDRINFOEXW, - timeout: ?*timeval, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPLOOKUPSERVICE_COMPLETION_ROUTINE, - lpNameHandle: ?*HANDLE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn GetAddrInfoExCancel( - lpHandle: *HANDLE, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn GetAddrInfoExOverlappedResult( - lpOverlapped: *OVERLAPPED, -) callconv(.winapi) i32; - -pub extern "ws2_32" fn FreeAddrInfoExW( - pAddrInfoEx: ?*ADDRINFOEXW, -) callconv(.winapi) void; - -pub extern "ws2_32" fn getnameinfo( - pSockaddr: *const sockaddr, - SockaddrLength: i32, - pNodeBuffer: ?[*]u8, - NodeBufferSize: u32, - pServiceBuffer: ?[*]u8, - ServiceBufferName: u32, - Flags: i32, -) callconv(.winapi) i32; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 1e92b39c6f..36e038c641 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -268,7 +268,7 @@ pub const LOG = struct { pub const DEBUG = 7; }; -pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t; +pub const socket_t = fd_t; /// Obtains errno from the return value of a system function call. /// @@ -500,18 +500,7 @@ pub const GetSockNameError = error{ pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { if (native_os == .windows) { - const rc = windows.getpeername(sock, addr, addrlen); - if (rc == windows.ws2_32.SOCKET_ERROR) { - switch (windows.ws2_32.WSAGetLastError()) { - .NOTINITIALISED => unreachable, - .ENETDOWN => return error.NetworkDown, - .EFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value - .ENOTSOCK => return error.FileDescriptorNotASocket, - .EINVAL => return error.SocketNotBound, - else => |err| return windows.unexpectedWSAError(err), - } - } - return; + @compileError("use std.Io instead"); } else { const rc = system.getpeername(sock, addr, addrlen); switch (errno(rc)) { @@ -992,16 +981,7 @@ pub const PollError = error{ pub fn poll(fds: []pollfd, timeout: i32) PollError!usize { if (native_os == .windows) { - switch (windows.poll(fds.ptr, @intCast(fds.len), timeout)) { - windows.ws2_32.SOCKET_ERROR => switch (windows.ws2_32.WSAGetLastError()) { - .NOTINITIALISED => unreachable, - .ENETDOWN => return error.NetworkDown, - .ENOBUFS => return error.SystemResources, - // TODO: handle more errors - else => |err| return windows.unexpectedWSAError(err), - }, - else => |rc| return @intCast(rc), - } + @compileError("use std.Io instead"); } while (true) { const fds_count = cast(nfds_t, fds.len) orelse return error.SystemResources; @@ -1071,18 +1051,7 @@ pub const SetSockOptError = error{ /// Set a socket's options. pub fn setsockopt(fd: socket_t, level: i32, optname: u32, opt: []const u8) SetSockOptError!void { if (native_os == .windows) { - const rc = windows.ws2_32.setsockopt(fd, level, @intCast(optname), opt.ptr, @intCast(opt.len)); - if (rc == windows.ws2_32.SOCKET_ERROR) { - switch (windows.ws2_32.WSAGetLastError()) { - .NOTINITIALISED => unreachable, - .ENETDOWN => return error.NetworkDown, - .EFAULT => unreachable, - .ENOTSOCK => return error.FileDescriptorNotASocket, - .EINVAL => return error.SocketNotBound, - else => |err| return windows.unexpectedWSAError(err), - } - } - return; + @compileError("use std.Io instead"); } else { switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(opt.len)))) { .SUCCESS => {}, diff --git a/test/standalone/coff_dwarf/build.zig b/test/standalone/coff_dwarf/build.zig index 0245154dbb..d35e744a6c 100644 --- a/test/standalone/coff_dwarf/build.zig +++ b/test/standalone/coff_dwarf/build.zig @@ -46,9 +46,6 @@ pub fn build(b: *std.Build) void { lib.root_module.addCSourceFile(.{ .file = b.path("shared_lib.c"), .flags = &.{"-gdwarf"} }); exe.root_module.linkLibrary(lib); - if (target.result.os.tag == .windows) - exe.root_module.linkSystemLibrary("ws2_32", .{}); - const run = b.addRunArtifact(exe); run.expectExitCode(0); run.skip_foreign_checks = true; diff --git a/test/standalone/issue_5825/build.zig b/test/standalone/issue_5825/build.zig index e4bc348d78..e102febe2d 100644 --- a/test/standalone/issue_5825/build.zig +++ b/test/standalone/issue_5825/build.zig @@ -34,7 +34,6 @@ pub fn build(b: *std.Build) void { exe.subsystem = .console; exe.root_module.linkSystemLibrary("kernel32", .{}); exe.root_module.linkSystemLibrary("ntdll", .{}); - exe.root_module.linkSystemLibrary("ws2_32", .{}); exe.root_module.addObject(obj); // TODO: actually check the output diff --git a/test/standalone/mix_o_files/build.zig b/test/standalone/mix_o_files/build.zig index 6ca7877058..12b90f3624 100644 --- a/test/standalone/mix_o_files/build.zig +++ b/test/standalone/mix_o_files/build.zig @@ -16,9 +16,6 @@ pub fn build(b: *std.Build) void { }), }); - if (target.result.os.tag == .windows) - obj.root_module.linkSystemLibrary("ws2_32", .{}); - const exe = b.addExecutable(.{ .name = "test", .root_module = b.createModule(.{ diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 3e9378eee0..444f5fd7bc 100644 --- a/test/standalone/shared_library/build.zig +++ b/test/standalone/shared_library/build.zig @@ -24,9 +24,6 @@ pub fn build(b: *std.Build) void { }), }); - if (target.result.os.tag == .windows) - lib.root_module.linkSystemLibrary("ws2_32", .{}); - const exe = b.addExecutable(.{ .name = exe_name, .root_module = b.createModule(.{ diff --git a/test/standalone/test_obj_link_run/build.zig b/test/standalone/test_obj_link_run/build.zig index 24e0e961e7..d1c9c8cb2a 100644 --- a/test/standalone/test_obj_link_run/build.zig +++ b/test/standalone/test_obj_link_run/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *std.Build) void { if (is_windows) { test_obj.root_module.linkSystemLibrary("ntdll", .{}); test_obj.root_module.linkSystemLibrary("kernel32", .{}); - test_obj.root_module.linkSystemLibrary("ws2_32", .{}); } const test_exe_mod = b.createModule(.{ diff --git a/test/standalone/windows_argv/build.zig b/test/standalone/windows_argv/build.zig index 6d20b389c6..cf83ecc5d4 100644 --- a/test/standalone/windows_argv/build.zig +++ b/test/standalone/windows_argv/build.zig @@ -20,7 +20,6 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }), }); - lib_gnu.root_module.linkSystemLibrary("ws2_32", .{}); const verify_gnu = b.addExecutable(.{ .name = "verify-gnu", @@ -103,7 +102,6 @@ pub fn build(b: *std.Build) !void { .flags = &.{ "-DUNICODE", "-D_UNICODE" }, }); verify_msvc.root_module.linkLibrary(lib_msvc); - verify_msvc.root_module.linkSystemLibrary("ws2_32", .{}); verify_msvc.root_module.link_libc = true; const run_msvc = b.addRunArtifact(fuzz); diff --git a/test/tests.zig b/test/tests.zig index 5e0d22682e..1531471e95 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2587,7 +2587,6 @@ fn addOneModuleTest( compile_c.linkSystemLibrary("advapi32", .{}); } compile_c.linkSystemLibrary("crypt32", .{}); - compile_c.linkSystemLibrary("ws2_32", .{}); compile_c.linkSystemLibrary("ole32", .{}); } } diff --git a/tools/incr-check.zig b/tools/incr-check.zig index 8eb985408e..453139609c 100644 --- a/tools/incr-check.zig +++ b/tools/incr-check.zig @@ -148,7 +148,6 @@ pub fn main(init: std.process.Init) !void { "--global-cache-dir", ".global-cache", }); - if (target.resolved.os.tag == .windows) try child_args.append(arena, "-lws2_32"); try child_args.append(arena, "--listen=-"); if (opt_resolved_lib_dir) |resolved_lib_dir| { @@ -190,9 +189,6 @@ pub fn main(init: std.process.Init) !void { opt_resolved_lib_dir.?, // verified earlier }); - if (target.resolved.os.tag == .windows) - try cc_child_args.append(arena, "-lws2_32"); - try cc_child_args.append(arena, "-o"); }