diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-10-21 10:30:06 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-10-29 06:20:51 -0700 |
| commit | ab003cd0545e54e66410b8e67136d4ef079b3198 (patch) | |
| tree | c97ce15f2daccb5e5a807bd99a400bea218a24ed /lib/std | |
| parent | dab8dd5e0306af4ef9b2388cfa8012ea596920ae (diff) | |
| download | zig-ab003cd0545e54e66410b8e67136d4ef079b3198.tar.gz zig-ab003cd0545e54e66410b8e67136d4ef079b3198.zip | |
std.Io.Threaded: implement netLookup for Windows
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/Io/Threaded.zig | 77 | ||||
| -rw-r--r-- | lib/std/os/windows/ws2_32.zig | 62 |
2 files changed, 108 insertions, 31 deletions
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 29934320d3..fbbd9a985c 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -4058,8 +4058,81 @@ fn netLookupFallible( assert(name.len <= HostName.max_len); if (is_windows) { - // TODO use GetAddrInfoExW / GetAddrInfoExCancel - @compileError("TODO"); + 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[0..port.len]) |byte, *wide| wide.* = 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 = 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) { + try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel + // 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)); + switch (rc) { + @as(ws2_32.WinsockError, @enumFromInt(0)) => break, + .EINTR => continue, + .ECANCELLED, .E_CANCELLED => return error.Canceled, + .NOTINITIALISED => { + try initializeWsa(t); + continue; + }, + .TRY_AGAIN => return error.NameServerFailure, + .EINVAL => |err| return wsaErrorBug(err), + .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, + else => |err| return windows.unexpectedWSAError(err), + } + } + 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; + const storage: WsaAddress = .{ .any = addr.* }; + try resolved.putOne(t_io, .{ .address = addressFromWsa(&storage) }); + + if (info.canonname) |n| { + if (canon_name == null) { + canon_name = n; + } + } + } + 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], + } }); + } + return; } // On Linux, glibc provides getaddrinfo_a which is capable of supporting our semantics. diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index b40f84af76..c10759b153 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -702,28 +702,32 @@ 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_ALL = 0; -pub const NS_SAP = 1; -pub const NS_NDS = 2; -pub const NS_PEER_BROWSE = 3; -pub const NS_SLP = 5; -pub const NS_DHCP = 6; -pub const NS_TCPIP_LOCAL = 10; -pub const NS_TCPIP_HOSTS = 11; -pub const NS_DNS = 12; -pub const NS_NETBT = 13; -pub const NS_WINS = 14; -pub const NS_NLA = 15; -pub const NS_NBP = 20; -pub const NS_MS = 30; -pub const NS_STDA = 31; -pub const NS_NTDS = 32; -pub const NS_EMAIL = 37; -pub const NS_X500 = 40; -pub const NS_NIS = 41; -pub const NS_NISPLUS = 42; -pub const NS_WRQ = 50; -pub const NS_NETDES = 60; + +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; @@ -1086,12 +1090,12 @@ pub const ADDRINFOEXW = extern struct { socktype: i32, protocol: i32, addrlen: usize, - canonname: [*:0]u16, - addr: *sockaddr, - blob: *anyopaque, + canonname: ?[*:0]u16, + addr: ?*sockaddr, + blob: ?*anyopaque, bloblen: usize, - provider: *GUID, - next: *ADDRINFOEXW, + provider: ?*GUID, + next: ?*ADDRINFOEXW, }; pub const sockaddr = extern struct { @@ -2101,7 +2105,7 @@ pub extern "mswsock" fn EnumProtocolsW( ) callconv(.winapi) i32; pub extern "mswsock" fn GetAddressByNameW( - dwNameSpace: u32, + dwNameSpace: NS, lpServiceType: *GUID, lpServiceName: ?[*:0]u16, lpiProtocols: ?*i32, @@ -2127,7 +2131,7 @@ pub extern "mswsock" fn GetNameByTypeW( pub extern "ws2_32" fn GetAddrInfoExW( pName: ?[*:0]const u16, pServiceName: ?[*:0]const u16, - dwNameSpace: DWORD, + dwNameSpace: NS, lpNspId: ?*GUID, hints: ?*const ADDRINFOEXW, ppResult: **ADDRINFOEXW, |
