std.Io.Threaded: implement netLookup for Windows

This commit is contained in:
Andrew Kelley 2025-10-21 10:30:06 -07:00
parent dab8dd5e03
commit ab003cd054
2 changed files with 108 additions and 31 deletions

View File

@ -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.

View File

@ -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,