diff options
| author | Jonathan Marler <johnnymarler@gmail.com> | 2020-05-31 10:07:51 -0600 |
|---|---|---|
| committer | Jonathan Marler <johnnymarler@gmail.com> | 2020-05-31 10:07:51 -0600 |
| commit | 58fb5b29b690dd868c7f69631fe59eae48fc9f4b (patch) | |
| tree | e489cbd1096b9d1d08e26067abfc6dcfad594cdf /lib/std | |
| parent | 2bae91e7697dfcaee7e250c813715fc4051ac51a (diff) | |
| download | zig-58fb5b29b690dd868c7f69631fe59eae48fc9f4b.tar.gz zig-58fb5b29b690dd868c7f69631fe59eae48fc9f4b.zip | |
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
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/net.zig | 58 | ||||
| -rw-r--r-- | lib/std/os.zig | 23 | ||||
| -rw-r--r-- | lib/std/os/bits/windows.zig | 9 | ||||
| -rw-r--r-- | lib/std/os/windows/ws2_32.zig | 12 |
4 files changed, 61 insertions, 41 deletions
diff --git a/lib/std/net.zig b/lib/std/net.zig index f60bc74925..ea133b1e67 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -452,37 +452,33 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* }; var res: *os.addrinfo = undefined; const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res); - if (builtin.os.tag == .windows) { - const ws2_32 = os.windows.ws2_32; - if (rc != 0) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) { - .WSATRY_AGAIN => return error.TemporaryNameServerFailure, - .WSANO_RECOVERY => return error.NameServerFailure, - .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, - .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory, - .WSAHOST_NOT_FOUND => return error.UnknownHostName, - .WSATYPE_NOT_FOUND => return error.ServiceUnavailable, - .WSAEINVAL => unreachable, - .WSAESOCKTNOSUPPORT => unreachable, - else => |err| return os.windows.unexpectedWSAError(err), - }; - } else { - switch (rc) { - @intToEnum(sys.EAI, 0) => {}, - .ADDRFAMILY => return error.HostLacksNetworkAddresses, - .AGAIN => return error.TemporaryNameServerFailure, - .BADFLAGS => unreachable, // Invalid hints - .FAIL => return error.NameServerFailure, - .FAMILY => return error.AddressFamilyNotSupported, - .MEMORY => return error.OutOfMemory, - .NODATA => return error.HostLacksNetworkAddresses, - .NONAME => return error.UnknownHostName, - .SERVICE => return error.ServiceUnavailable, - .SOCKTYPE => unreachable, // Invalid socket type requested in hints - .SYSTEM => switch (os.errno(-1)) { - else => |e| return os.unexpectedErrno(e), - }, - else => unreachable, - } + if (builtin.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) { + @intToEnum(os.windows.ws2_32.WinsockError, 0) => {}, + .WSATRY_AGAIN => return error.TemporaryNameServerFailure, + .WSANO_RECOVERY => return error.NameServerFailure, + .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, + .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory, + .WSAHOST_NOT_FOUND => return error.UnknownHostName, + .WSATYPE_NOT_FOUND => return error.ServiceUnavailable, + .WSAEINVAL => unreachable, + .WSAESOCKTNOSUPPORT => unreachable, + else => |err| return os.windows.unexpectedWSAError(err), + } else switch (rc) { + @intToEnum(sys.EAI, 0) => {}, + .ADDRFAMILY => return error.HostLacksNetworkAddresses, + .AGAIN => return error.TemporaryNameServerFailure, + .BADFLAGS => unreachable, // Invalid hints + .FAIL => return error.NameServerFailure, + .FAMILY => return error.AddressFamilyNotSupported, + .MEMORY => return error.OutOfMemory, + .NODATA => return error.HostLacksNetworkAddresses, + .NONAME => return error.UnknownHostName, + .SERVICE => return error.ServiceUnavailable, + .SOCKTYPE => unreachable, // Invalid socket type requested in hints + .SYSTEM => switch (os.errno(-1)) { + else => |e| return os.unexpectedErrno(e), + }, + else => unreachable, } defer sys.freeaddrinfo(res); diff --git a/lib/std/os.zig b/lib/std/os.zig index 79ceffb789..963f919cee 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2447,17 +2447,29 @@ pub const SocketError = error{ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t { if (builtin.os.tag == .windows) { - // NOTE: cannot remove SOCK_NONBLOCK and SOCK_CLOEXEC from socket_type because - // windows does not define this flags yet - const rc = windows.ws2_32.socket(@intCast(c_int, domain), @intCast(c_int, socket_type), @intCast(c_int, protocol)); - if (rc != windows.ws2_32.INVALID_SOCKET) return rc; - switch (windows.ws2_32.WSAGetLastError()) { + // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations + const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC); + const flags : u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0; + const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), + @intCast(c_int, protocol), null, 0, flags); + if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { .WSAEMFILE => return error.ProcessFdQuotaExceeded, .WSAENOBUFS => return error.SystemResources, .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, else => |err| return windows.unexpectedWSAError(err), + }; + errdefer windows.closesocket(rc) catch unreachable; + if ((socket_type & SOCK_NONBLOCK) != 0) { + var mode : c_ulong = 1; // nonblocking + if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) { + switch (windows.ws2_32.WSAGetLastError()) { + // have not identified any error codes that should be handled yet + else => unreachable, + } + } } + return rc; } 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 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, else => |err| return windows.unexpectedWSAError(err), } + return; } while (true) { diff --git a/lib/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig index 505b348010..4988cafbe0 100644 --- a/lib/std/os/bits/windows.zig +++ b/lib/std/os/bits/windows.zig @@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW; pub const SOCK_RDM = ws2_32.SOCK_RDM; pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET; +/// WARNING: this flag is not supported by windows socket functions directly, +/// it is only supported by std.os.socket. Be sure that this value does +/// not share any bits with any of the SOCK_* values. +pub const SOCK_CLOEXEC = 0x10000; +/// WARNING: this flag is not supported by windows socket functions directly, +/// it is only supported by std.os.socket. Be sure that this value does +/// not share any bits with any of the SOCK_* values. +pub const SOCK_NONBLOCK = 0x20000; + pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP; pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP; pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM; diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index 6c1a712040..d1c400f2b3 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -174,6 +174,8 @@ pub const AI_SECURE = 0x08000; pub const AI_RETURN_PREFERRED_NAMES = 0x10000; pub const AI_DISABLE_IDN_ENCODING = 0x80000; +pub const FIONBIO = -2147195266; + pub const sockaddr = extern struct { family: ADDRESS_FAMILY, data: [14]u8, @@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl( lpOverlapped: ?*WSAOVERLAPPED, lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, ) callconv(.Stdcall) c_int; -pub extern "ws2_32" fn socket( - af: c_int, - type: c_int, - protocol: c_int, -) callconv(.Stdcall) SOCKET; pub extern "ws2_32" fn accept( s: SOCKET, addr: ?*sockaddr, @@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo( pub extern "ws2_32" fn freeaddrinfo( pAddrInfo: *addrinfo, ) callconv(.Stdcall) void; +pub extern "ws2_32" fn ioctlsocket( + s: SOCKET, + cmd: c_long, + argp: *c_ulong, +) callconv(.Stdcall) c_int; |
