Skip to content

Commit 1eb311a

Browse files
committed
std.net.getAddressList: call WSAStartup on Windows
1 parent 749b335 commit 1eb311a

File tree

2 files changed

+93
-29
lines changed

2 files changed

+93
-29
lines changed

lib/std/net.zig

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,79 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
746746
const arena = result.arena.allocator();
747747
errdefer result.deinit();
748748

749-
if (builtin.target.os.tag == .windows or builtin.link_libc) {
749+
if (builtin.target.os.tag == .windows) {
750+
const name_c = try std.cstr.addNullByte(allocator, name);
751+
defer allocator.free(name_c);
752+
753+
const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
754+
defer allocator.free(port_c);
755+
756+
const ws2_32 = os.windows.ws2_32;
757+
const hints = os.addrinfo{
758+
.flags = ws2_32.AI.NUMERICSERV,
759+
.family = os.AF.UNSPEC,
760+
.socktype = os.SOCK.STREAM,
761+
.protocol = os.IPPROTO.TCP,
762+
.canonname = null,
763+
.addr = null,
764+
.addrlen = 0,
765+
.next = null,
766+
};
767+
var res: *os.addrinfo = undefined;
768+
var first = true;
769+
while (true) {
770+
const rc = ws2_32.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);
771+
switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
772+
@intToEnum(os.windows.ws2_32.WinsockError, 0) => break,
773+
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
774+
.WSANO_RECOVERY => return error.NameServerFailure,
775+
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
776+
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
777+
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
778+
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
779+
.WSAEINVAL => unreachable,
780+
.WSAESOCKTNOSUPPORT => unreachable,
781+
.WSANOTINITIALISED => {
782+
if (!first) return error.Unexpected;
783+
first = false;
784+
try os.windows.callWSAStartup();
785+
continue;
786+
},
787+
else => |err| return os.windows.unexpectedWSAError(err),
788+
}
789+
}
790+
defer ws2_32.freeaddrinfo(res);
791+
792+
const addr_count = blk: {
793+
var count: usize = 0;
794+
var it: ?*os.addrinfo = res;
795+
while (it) |info| : (it = info.next) {
796+
if (info.addr != null) {
797+
count += 1;
798+
}
799+
}
800+
break :blk count;
801+
};
802+
result.addrs = try arena.alloc(Address, addr_count);
803+
804+
var it: ?*os.addrinfo = res;
805+
var i: usize = 0;
806+
while (it) |info| : (it = info.next) {
807+
const addr = info.addr orelse continue;
808+
result.addrs[i] = Address.initPosix(@alignCast(4, addr));
809+
810+
if (info.canonname) |n| {
811+
if (result.canon_name == null) {
812+
result.canon_name = try arena.dupe(u8, mem.sliceTo(n, 0));
813+
}
814+
}
815+
i += 1;
816+
}
817+
818+
return result;
819+
}
820+
821+
if (builtin.link_libc) {
750822
const name_c = try std.cstr.addNullByte(allocator, name);
751823
defer allocator.free(name_c);
752824

@@ -765,19 +837,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
765837
.next = null,
766838
};
767839
var res: *os.addrinfo = undefined;
768-
const rc = sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);
769-
if (builtin.target.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
770-
@intToEnum(os.windows.ws2_32.WinsockError, 0) => {},
771-
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
772-
.WSANO_RECOVERY => return error.NameServerFailure,
773-
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
774-
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
775-
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
776-
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
777-
.WSAEINVAL => unreachable,
778-
.WSAESOCKTNOSUPPORT => unreachable,
779-
else => |err| return os.windows.unexpectedWSAError(err),
780-
} else switch (rc) {
840+
switch (sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
781841
@intToEnum(sys.EAI, 0) => {},
782842
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
783843
.AGAIN => return error.TemporaryNameServerFailure,
@@ -824,6 +884,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
824884

825885
return result;
826886
}
887+
827888
if (builtin.target.os.tag == .linux) {
828889
const flags = std.c.AI.NUMERICSERV;
829890
const family = os.AF.UNSPEC;

lib/std/os/windows.zig

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,23 @@ pub fn WSACleanup() !void {
12961296

12971297
var wsa_startup_mutex: std.Thread.Mutex = .{};
12981298

1299+
pub fn callWSAStartup() !void {
1300+
wsa_startup_mutex.lock();
1301+
defer wsa_startup_mutex.unlock();
1302+
1303+
// Here we could use a flag to prevent multiple threads to prevent
1304+
// multiple calls to WSAStartup, but it doesn't matter. We're globally
1305+
// leaking the resource intentionally, and the mutex already prevents
1306+
// data races within the WSAStartup function.
1307+
_ = WSAStartup(2, 2) catch |err| switch (err) {
1308+
error.SystemNotAvailable => return error.SystemResources,
1309+
error.VersionNotSupported => return error.Unexpected,
1310+
error.BlockingOperationInProgress => return error.Unexpected,
1311+
error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
1312+
error.Unexpected => return error.Unexpected,
1313+
};
1314+
}
1315+
12991316
/// Microsoft requires WSAStartup to be called to initialize, or else
13001317
/// WSASocketW will return WSANOTINITIALISED.
13011318
/// Since this is a standard library, we do not have the luxury of
@@ -1338,21 +1355,7 @@ pub fn WSASocketW(
13381355
.WSANOTINITIALISED => {
13391356
if (!first) return error.Unexpected;
13401357
first = false;
1341-
1342-
wsa_startup_mutex.lock();
1343-
defer wsa_startup_mutex.unlock();
1344-
1345-
// Here we could use a flag to prevent multiple threads to prevent
1346-
// multiple calls to WSAStartup, but it doesn't matter. We're globally
1347-
// leaking the resource intentionally, and the mutex already prevents
1348-
// data races within the WSAStartup function.
1349-
_ = WSAStartup(2, 2) catch |err| switch (err) {
1350-
error.SystemNotAvailable => return error.SystemResources,
1351-
error.VersionNotSupported => return error.Unexpected,
1352-
error.BlockingOperationInProgress => return error.Unexpected,
1353-
error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
1354-
error.Unexpected => return error.Unexpected,
1355-
};
1358+
try callWSAStartup();
13561359
continue;
13571360
},
13581361
else => |err| return unexpectedWSAError(err),

0 commit comments

Comments
 (0)