authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-16 17:11:07-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-17 00:08:42-07:00
log86308ba1e11a083f4ec91cf3b0e81a791892f851
tree735632091fefa922056cd0a497870799f629722b
parent62e3fdcf4faf6bdfdfd468d54b540eec74a8bdae

std.net.getAddressList: call WSAStartup on Windows


2 files changed, 93 insertions(+), 29 deletions(-)

lib/std/net.zig+75-14
......@@ -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+18-15
......@@ -1296,6 +1296,23 @@ pub fn WSACleanup() !void {
12961296
12971297var wsa_startup_mutex: std.Thread.Mutex = .{};
12981298
1299pub 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),