| ... | ... | @@ -4058,8 +4058,81 @@ fn netLookupFallible( |
| 4058 | 4058 | assert(name.len <= HostName.max_len); |
| 4059 | 4059 | |
| 4060 | 4060 | 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; |
| 4063 | 4136 | } |
| 4064 | 4137 | |
| 4065 | 4138 | // On Linux, glibc provides getaddrinfo_a which is capable of supporting our semantics. |