Skip to content

Commit 58fb5b2

Browse files
committed
more windows network fixes
* support posix SOCK_NONBLOCK and SOCK_CLOEXEC flags on windows * fix bugs in os.socket and os.connect to return at the correct place
1 parent 2bae91e commit 58fb5b2

File tree

4 files changed

+61
-41
lines changed

4 files changed

+61
-41
lines changed

lib/std/net.zig

+27-31
Original file line numberDiff line numberDiff line change
@@ -452,37 +452,33 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
452452
};
453453
var res: *os.addrinfo = undefined;
454454
const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res);
455-
if (builtin.os.tag == .windows) {
456-
const ws2_32 = os.windows.ws2_32;
457-
if (rc != 0) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
458-
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
459-
.WSANO_RECOVERY => return error.NameServerFailure,
460-
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
461-
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
462-
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
463-
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
464-
.WSAEINVAL => unreachable,
465-
.WSAESOCKTNOSUPPORT => unreachable,
466-
else => |err| return os.windows.unexpectedWSAError(err),
467-
};
468-
} else {
469-
switch (rc) {
470-
@intToEnum(sys.EAI, 0) => {},
471-
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
472-
.AGAIN => return error.TemporaryNameServerFailure,
473-
.BADFLAGS => unreachable, // Invalid hints
474-
.FAIL => return error.NameServerFailure,
475-
.FAMILY => return error.AddressFamilyNotSupported,
476-
.MEMORY => return error.OutOfMemory,
477-
.NODATA => return error.HostLacksNetworkAddresses,
478-
.NONAME => return error.UnknownHostName,
479-
.SERVICE => return error.ServiceUnavailable,
480-
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
481-
.SYSTEM => switch (os.errno(-1)) {
482-
else => |e| return os.unexpectedErrno(e),
483-
},
484-
else => unreachable,
485-
}
455+
if (builtin.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
456+
@intToEnum(os.windows.ws2_32.WinsockError, 0) => {},
457+
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
458+
.WSANO_RECOVERY => return error.NameServerFailure,
459+
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
460+
.WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
461+
.WSAHOST_NOT_FOUND => return error.UnknownHostName,
462+
.WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
463+
.WSAEINVAL => unreachable,
464+
.WSAESOCKTNOSUPPORT => unreachable,
465+
else => |err| return os.windows.unexpectedWSAError(err),
466+
} else switch (rc) {
467+
@intToEnum(sys.EAI, 0) => {},
468+
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
469+
.AGAIN => return error.TemporaryNameServerFailure,
470+
.BADFLAGS => unreachable, // Invalid hints
471+
.FAIL => return error.NameServerFailure,
472+
.FAMILY => return error.AddressFamilyNotSupported,
473+
.MEMORY => return error.OutOfMemory,
474+
.NODATA => return error.HostLacksNetworkAddresses,
475+
.NONAME => return error.UnknownHostName,
476+
.SERVICE => return error.ServiceUnavailable,
477+
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
478+
.SYSTEM => switch (os.errno(-1)) {
479+
else => |e| return os.unexpectedErrno(e),
480+
},
481+
else => unreachable,
486482
}
487483
defer sys.freeaddrinfo(res);
488484

lib/std/os.zig

+18-5
Original file line numberDiff line numberDiff line change
@@ -2447,17 +2447,29 @@ pub const SocketError = error{
24472447

24482448
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {
24492449
if (builtin.os.tag == .windows) {
2450-
// NOTE: cannot remove SOCK_NONBLOCK and SOCK_CLOEXEC from socket_type because
2451-
// windows does not define this flags yet
2452-
const rc = windows.ws2_32.socket(@intCast(c_int, domain), @intCast(c_int, socket_type), @intCast(c_int, protocol));
2453-
if (rc != windows.ws2_32.INVALID_SOCKET) return rc;
2454-
switch (windows.ws2_32.WSAGetLastError()) {
2450+
// NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
2451+
const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
2452+
const flags : u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0;
2453+
const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type),
2454+
@intCast(c_int, protocol), null, 0, flags);
2455+
if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) {
24552456
.WSAEMFILE => return error.ProcessFdQuotaExceeded,
24562457
.WSAENOBUFS => return error.SystemResources,
24572458
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
24582459
.WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,
24592460
else => |err| return windows.unexpectedWSAError(err),
2461+
};
2462+
errdefer windows.closesocket(rc) catch unreachable;
2463+
if ((socket_type & SOCK_NONBLOCK) != 0) {
2464+
var mode : c_ulong = 1; // nonblocking
2465+
if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) {
2466+
switch (windows.ws2_32.WSAGetLastError()) {
2467+
// have not identified any error codes that should be handled yet
2468+
else => unreachable,
2469+
}
2470+
}
24602471
}
2472+
return rc;
24612473
}
24622474

24632475
const have_sock_flags = comptime !std.Target.current.isDarwin();
@@ -2855,6 +2867,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
28552867
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
28562868
else => |err| return windows.unexpectedWSAError(err),
28572869
}
2870+
return;
28582871
}
28592872

28602873
while (true) {

lib/std/os/bits/windows.zig

+9
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW;
221221
pub const SOCK_RDM = ws2_32.SOCK_RDM;
222222
pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET;
223223

224+
/// WARNING: this flag is not supported by windows socket functions directly,
225+
/// it is only supported by std.os.socket. Be sure that this value does
226+
/// not share any bits with any of the SOCK_* values.
227+
pub const SOCK_CLOEXEC = 0x10000;
228+
/// WARNING: this flag is not supported by windows socket functions directly,
229+
/// it is only supported by std.os.socket. Be sure that this value does
230+
/// not share any bits with any of the SOCK_* values.
231+
pub const SOCK_NONBLOCK = 0x20000;
232+
224233
pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP;
225234
pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP;
226235
pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM;

lib/std/os/windows/ws2_32.zig

+7-5
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ pub const AI_SECURE = 0x08000;
174174
pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
175175
pub const AI_DISABLE_IDN_ENCODING = 0x80000;
176176

177+
pub const FIONBIO = -2147195266;
178+
177179
pub const sockaddr = extern struct {
178180
family: ADDRESS_FAMILY,
179181
data: [14]u8,
@@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl(
724726
lpOverlapped: ?*WSAOVERLAPPED,
725727
lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
726728
) callconv(.Stdcall) c_int;
727-
pub extern "ws2_32" fn socket(
728-
af: c_int,
729-
type: c_int,
730-
protocol: c_int,
731-
) callconv(.Stdcall) SOCKET;
732729
pub extern "ws2_32" fn accept(
733730
s: SOCKET,
734731
addr: ?*sockaddr,
@@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo(
788785
pub extern "ws2_32" fn freeaddrinfo(
789786
pAddrInfo: *addrinfo,
790787
) callconv(.Stdcall) void;
788+
pub extern "ws2_32" fn ioctlsocket(
789+
s: SOCKET,
790+
cmd: c_long,
791+
argp: *c_ulong,
792+
) callconv(.Stdcall) c_int;

0 commit comments

Comments
 (0)