authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-21 10:30:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
logab003cd0545e54e66410b8e67136d4ef079b3198
treec97ce15f2daccb5e5a807bd99a400bea218a24ed
parentdab8dd5e0306af4ef9b2388cfa8012ea596920ae

std.Io.Threaded: implement netLookup for Windows


2 files changed, 108 insertions(+), 31 deletions(-)

lib/std/Io/Threaded.zig+75-2
......@@ -4058,8 +4058,81 @@ fn netLookupFallible(
40584058 assert(name.len <= HostName.max_len);
40594059
40604060 if (is_windows) {
4061 // TODO use GetAddrInfoExW / GetAddrInfoExCancel
4062 @compileError("TODO");
4061 var name_buffer: [HostName.max_len + 1]u16 = undefined;
4062 const name_len = std.unicode.wtf8ToWtf16Le(&name_buffer, host_name.bytes) catch
4063 unreachable; // HostName is prevalidated.
4064 name_buffer[name_len] = 0;
4065 const name_w = name_buffer[0..name_len :0];
4066
4067 var port_buffer: [8]u8 = undefined;
4068 var port_buffer_wide: [8]u16 = undefined;
4069 const port = std.fmt.bufPrint(&port_buffer, "{d}", .{options.port}) catch
4070 unreachable; // `port_buffer` is big enough for decimal u16.
4071 for (port, port_buffer[0..port.len]) |byte, *wide| wide.* = byte;
4072 port_buffer_wide[port.len] = 0;
4073 const port_w = port_buffer_wide[0..port.len :0];
4074
4075 const hints: ws2_32.ADDRINFOEXW = .{
4076 .flags = .{ .NUMERICSERV = true },
4077 .family = posix.AF.UNSPEC,
4078 .socktype = posix.SOCK.STREAM,
4079 .protocol = posix.IPPROTO.TCP,
4080 .canonname = null,
4081 .addr = null,
4082 .addrlen = 0,
4083 .blob = null,
4084 .bloblen = 0,
4085 .provider = null,
4086 .next = null,
4087 };
4088 var res: *ws2_32.ADDRINFOEXW = undefined;
4089 const timeout: ?*ws2_32.timeval = null;
4090 while (true) {
4091 try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
4092 // TODO make this append to the queue eagerly rather than blocking until
4093 // the whole thing finishes
4094 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null));
4095 switch (rc) {
4096 @as(ws2_32.WinsockError, @enumFromInt(0)) => break,
4097 .EINTR => continue,
4098 .ECANCELLED, .E_CANCELLED => return error.Canceled,
4099 .NOTINITIALISED => {
4100 try initializeWsa(t);
4101 continue;
4102 },
4103 .TRY_AGAIN => return error.NameServerFailure,
4104 .EINVAL => |err| return wsaErrorBug(err),
4105 .NO_RECOVERY => return error.NameServerFailure,
4106 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4107 .NOT_ENOUGH_MEMORY => return error.SystemResources,
4108 .HOST_NOT_FOUND => return error.UnknownHostName,
4109 .TYPE_NOT_FOUND => return error.ProtocolUnsupportedByAddressFamily,
4110 .ESOCKTNOSUPPORT => return error.ProtocolUnsupportedBySystem,
4111 else => |err| return windows.unexpectedWSAError(err),
4112 }
4113 }
4114 defer ws2_32.FreeAddrInfoExW(res);
4115
4116 var it: ?*ws2_32.ADDRINFOEXW = res;
4117 var canon_name: ?[*:0]const u16 = null;
4118 while (it) |info| : (it = info.next) {
4119 const addr = info.addr orelse continue;
4120 const storage: WsaAddress = .{ .any = addr.* };
4121 try resolved.putOne(t_io, .{ .address = addressFromWsa(&storage) });
4122
4123 if (info.canonname) |n| {
4124 if (canon_name == null) {
4125 canon_name = n;
4126 }
4127 }
4128 }
4129 if (canon_name) |n| {
4130 const len = std.unicode.wtf16LeToWtf8(options.canonical_name_buffer, std.mem.sliceTo(n, 0));
4131 try resolved.putOne(t_io, .{ .canonical_name = .{
4132 .bytes = options.canonical_name_buffer[0..len],
4133 } });
4134 }
4135 return;
40634136 }
40644137
40654138 // On Linux, glibc provides getaddrinfo_a which is capable of supporting our semantics.
lib/std/os/windows/ws2_32.zig+33-29
......@@ -702,28 +702,32 @@ pub const FIONBIO = -2147195266;
702702pub const ADDRINFOEX_VERSION_2 = 2;
703703pub const ADDRINFOEX_VERSION_3 = 3;
704704pub const ADDRINFOEX_VERSION_4 = 4;
705pub const NS_ALL = 0;
706pub const NS_SAP = 1;
707pub const NS_NDS = 2;
708pub const NS_PEER_BROWSE = 3;
709pub const NS_SLP = 5;
710pub const NS_DHCP = 6;
711pub const NS_TCPIP_LOCAL = 10;
712pub const NS_TCPIP_HOSTS = 11;
713pub const NS_DNS = 12;
714pub const NS_NETBT = 13;
715pub const NS_WINS = 14;
716pub const NS_NLA = 15;
717pub const NS_NBP = 20;
718pub const NS_MS = 30;
719pub const NS_STDA = 31;
720pub const NS_NTDS = 32;
721pub const NS_EMAIL = 37;
722pub const NS_X500 = 40;
723pub const NS_NIS = 41;
724pub const NS_NISPLUS = 42;
725pub const NS_WRQ = 50;
726pub const NS_NETDES = 60;
705
706pub const NS = enum(u32) {
707 ALL = 0,
708 SAP = 1,
709 NDS = 2,
710 PEER_BROWSE = 3,
711 SLP = 5,
712 DHCP = 6,
713 TCPIP_LOCAL = 10,
714 TCPIP_HOSTS = 11,
715 DNS = 12,
716 NETBT = 13,
717 WINS = 14,
718 NLA = 15,
719 NBP = 20,
720 MS = 30,
721 STDA = 31,
722 NTDS = 32,
723 EMAIL = 37,
724 X500 = 40,
725 NIS = 41,
726 NISPLUS = 42,
727 WRQ = 50,
728 NETDES = 60,
729};
730
727731pub const NI_NOFQDN = 1;
728732pub const NI_NUMERICHOST = 2;
729733pub const NI_NAMEREQD = 4;
......@@ -1086,12 +1090,12 @@ pub const ADDRINFOEXW = extern struct {
10861090 socktype: i32,
10871091 protocol: i32,
10881092 addrlen: usize,
1089 canonname: [*:0]u16,
1090 addr: *sockaddr,
1091 blob: *anyopaque,
1093 canonname: ?[*:0]u16,
1094 addr: ?*sockaddr,
1095 blob: ?*anyopaque,
10921096 bloblen: usize,
1093 provider: *GUID,
1094 next: *ADDRINFOEXW,
1097 provider: ?*GUID,
1098 next: ?*ADDRINFOEXW,
10951099};
10961100
10971101pub const sockaddr = extern struct {
......@@ -2101,7 +2105,7 @@ pub extern "mswsock" fn EnumProtocolsW(
21012105) callconv(.winapi) i32;
21022106
21032107pub extern "mswsock" fn GetAddressByNameW(
2104 dwNameSpace: u32,
2108 dwNameSpace: NS,
21052109 lpServiceType: *GUID,
21062110 lpServiceName: ?[*:0]u16,
21072111 lpiProtocols: ?*i32,
......@@ -2127,7 +2131,7 @@ pub extern "mswsock" fn GetNameByTypeW(
21272131pub extern "ws2_32" fn GetAddrInfoExW(
21282132 pName: ?[*:0]const u16,
21292133 pServiceName: ?[*:0]const u16,
2130 dwNameSpace: DWORD,
2134 dwNameSpace: NS,
21312135 lpNspId: ?*GUID,
21322136 hints: ?*const ADDRINFOEXW,
21332137 ppResult: **ADDRINFOEXW,