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(...@@ -4058,8 +4058,81 @@ fn netLookupFallible(
4058 assert(name.len <= HostName.max_len);4058 assert(name.len <= HostName.max_len);
40594059
4060 if (is_windows) {4060 if (is_windows) {
4061 // TODO use GetAddrInfoExW / GetAddrInfoExCancel4061 var name_buffer: [HostName.max_len + 1]u16 = undefined;
4062 @compileError("TODO");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;
4063 }4136 }
40644137
4065 // On Linux, glibc provides getaddrinfo_a which is capable of supporting our semantics.4138 // 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;...@@ -702,28 +702,32 @@ pub const FIONBIO = -2147195266;
702pub const ADDRINFOEX_VERSION_2 = 2;702pub const ADDRINFOEX_VERSION_2 = 2;
703pub const ADDRINFOEX_VERSION_3 = 3;703pub const ADDRINFOEX_VERSION_3 = 3;
704pub const ADDRINFOEX_VERSION_4 = 4;704pub const ADDRINFOEX_VERSION_4 = 4;
705pub const NS_ALL = 0;705
706pub const NS_SAP = 1;706pub const NS = enum(u32) {
707pub const NS_NDS = 2;707 ALL = 0,
708pub const NS_PEER_BROWSE = 3;708 SAP = 1,
709pub const NS_SLP = 5;709 NDS = 2,
710pub const NS_DHCP = 6;710 PEER_BROWSE = 3,
711pub const NS_TCPIP_LOCAL = 10;711 SLP = 5,
712pub const NS_TCPIP_HOSTS = 11;712 DHCP = 6,
713pub const NS_DNS = 12;713 TCPIP_LOCAL = 10,
714pub const NS_NETBT = 13;714 TCPIP_HOSTS = 11,
715pub const NS_WINS = 14;715 DNS = 12,
716pub const NS_NLA = 15;716 NETBT = 13,
717pub const NS_NBP = 20;717 WINS = 14,
718pub const NS_MS = 30;718 NLA = 15,
719pub const NS_STDA = 31;719 NBP = 20,
720pub const NS_NTDS = 32;720 MS = 30,
721pub const NS_EMAIL = 37;721 STDA = 31,
722pub const NS_X500 = 40;722 NTDS = 32,
723pub const NS_NIS = 41;723 EMAIL = 37,
724pub const NS_NISPLUS = 42;724 X500 = 40,
725pub const NS_WRQ = 50;725 NIS = 41,
726pub const NS_NETDES = 60;726 NISPLUS = 42,
727 WRQ = 50,
728 NETDES = 60,
729};
730
727pub const NI_NOFQDN = 1;731pub const NI_NOFQDN = 1;
728pub const NI_NUMERICHOST = 2;732pub const NI_NUMERICHOST = 2;
729pub const NI_NAMEREQD = 4;733pub const NI_NAMEREQD = 4;
...@@ -1086,12 +1090,12 @@ pub const ADDRINFOEXW = extern struct {...@@ -1086,12 +1090,12 @@ pub const ADDRINFOEXW = extern struct {
1086 socktype: i32,1090 socktype: i32,
1087 protocol: i32,1091 protocol: i32,
1088 addrlen: usize,1092 addrlen: usize,
1089 canonname: [*:0]u16,1093 canonname: ?[*:0]u16,
1090 addr: *sockaddr,1094 addr: ?*sockaddr,
1091 blob: *anyopaque,1095 blob: ?*anyopaque,
1092 bloblen: usize,1096 bloblen: usize,
1093 provider: *GUID,1097 provider: ?*GUID,
1094 next: *ADDRINFOEXW,1098 next: ?*ADDRINFOEXW,
1095};1099};
10961100
1097pub const sockaddr = extern struct {1101pub const sockaddr = extern struct {
...@@ -2101,7 +2105,7 @@ pub extern "mswsock" fn EnumProtocolsW(...@@ -2101,7 +2105,7 @@ pub extern "mswsock" fn EnumProtocolsW(
2101) callconv(.winapi) i32;2105) callconv(.winapi) i32;
21022106
2103pub extern "mswsock" fn GetAddressByNameW(2107pub extern "mswsock" fn GetAddressByNameW(
2104 dwNameSpace: u32,2108 dwNameSpace: NS,
2105 lpServiceType: *GUID,2109 lpServiceType: *GUID,
2106 lpServiceName: ?[*:0]u16,2110 lpServiceName: ?[*:0]u16,
2107 lpiProtocols: ?*i32,2111 lpiProtocols: ?*i32,
...@@ -2127,7 +2131,7 @@ pub extern "mswsock" fn GetNameByTypeW(...@@ -2127,7 +2131,7 @@ pub extern "mswsock" fn GetNameByTypeW(
2127pub extern "ws2_32" fn GetAddrInfoExW(2131pub extern "ws2_32" fn GetAddrInfoExW(
2128 pName: ?[*:0]const u16,2132 pName: ?[*:0]const u16,
2129 pServiceName: ?[*:0]const u16,2133 pServiceName: ?[*:0]const u16,
2130 dwNameSpace: DWORD,2134 dwNameSpace: NS,
2131 lpNspId: ?*GUID,2135 lpNspId: ?*GUID,
2132 hints: ?*const ADDRINFOEXW,2136 hints: ?*const ADDRINFOEXW,
2133 ppResult: **ADDRINFOEXW,2137 ppResult: **ADDRINFOEXW,