@@ -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.
0 commit comments