| author | |
| committer | |
| log | 58fb5b29b690dd868c7f69631fe59eae48fc9f4b |
| tree | e489cbd1096b9d1d08e26067abfc6dcfad594cdf |
| parent | 2bae91e7697dfcaee7e250c813715fc4051ac51a |
* support posix SOCK_NONBLOCK and SOCK_CLOEXEC flags on windows
* fix bugs in os.socket and os.connect to return at the correct place4 files changed, 61 insertions(+), 41 deletions(-)
lib/std/net.zig+27-31| ... | ... | @@ -452,37 +452,33 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 452 | 452 | }; |
| 453 | 453 | var res: *os.addrinfo = undefined; |
| 454 | 454 | 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, | |
| 486 | 482 | } |
| 487 | 483 | defer sys.freeaddrinfo(res); |
| 488 | 484 |
lib/std/os.zig+18-5| ... | ... | @@ -2447,17 +2447,29 @@ pub const SocketError = error{ |
| 2447 | 2447 | |
| 2448 | 2448 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t { |
| 2449 | 2449 | 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()) { | |
| 2455 | 2456 | .WSAEMFILE => return error.ProcessFdQuotaExceeded, |
| 2456 | 2457 | .WSAENOBUFS => return error.SystemResources, |
| 2457 | 2458 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, |
| 2458 | 2459 | .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, |
| 2459 | 2460 | 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 | } | |
| 2460 | 2471 | } |
| 2472 | return rc; | |
| 2461 | 2473 | } |
| 2462 | 2474 | |
| 2463 | 2475 | 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 |
| 2855 | 2867 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, |
| 2856 | 2868 | else => |err| return windows.unexpectedWSAError(err), |
| 2857 | 2869 | } |
| 2870 | return; | |
| 2858 | 2871 | } |
| 2859 | 2872 | |
| 2860 | 2873 | while (true) { |
lib/std/os/bits/windows.zig+9| ... | ... | @@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW; |
| 221 | 221 | pub const SOCK_RDM = ws2_32.SOCK_RDM; |
| 222 | 222 | pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET; |
| 223 | 223 | |
| 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 | ||
| 224 | 233 | pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP; |
| 225 | 234 | pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP; |
| 226 | 235 | pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM; |
lib/std/os/windows/ws2_32.zig+7-5| ... | ... | @@ -174,6 +174,8 @@ pub const AI_SECURE = 0x08000; |
| 174 | 174 | pub const AI_RETURN_PREFERRED_NAMES = 0x10000; |
| 175 | 175 | pub const AI_DISABLE_IDN_ENCODING = 0x80000; |
| 176 | 176 | |
| 177 | pub const FIONBIO = -2147195266; | |
| 178 | ||
| 177 | 179 | pub const sockaddr = extern struct { |
| 178 | 180 | family: ADDRESS_FAMILY, |
| 179 | 181 | data: [14]u8, |
| ... | ... | @@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl( |
| 724 | 726 | lpOverlapped: ?*WSAOVERLAPPED, |
| 725 | 727 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, |
| 726 | 728 | ) 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; | |
| 732 | 729 | pub extern "ws2_32" fn accept( |
| 733 | 730 | s: SOCKET, |
| 734 | 731 | addr: ?*sockaddr, |
| ... | ... | @@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo( |
| 788 | 785 | pub extern "ws2_32" fn freeaddrinfo( |
| 789 | 786 | pAddrInfo: *addrinfo, |
| 790 | 787 | ) 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; |