authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2020-05-31 10:07:51-06:00
committergravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2020-05-31 10:07:51-06:00
log58fb5b29b690dd868c7f69631fe59eae48fc9f4b
treee489cbd1096b9d1d08e26067abfc6dcfad594cdf
parent2bae91e7697dfcaee7e250c813715fc4051ac51a

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

4 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,37 +452,33 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
452 };452 };
453 var res: *os.addrinfo = undefined;453 var res: *os.addrinfo = undefined;
454 const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res);454 const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res);
455 if (builtin.os.tag == .windows) {455 if (builtin.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
456 const ws2_32 = os.windows.ws2_32;456 @intToEnum(os.windows.ws2_32.WinsockError, 0) => {},
457 if (rc != 0) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {457 .WSATRY_AGAIN => return error.TemporaryNameServerFailure,
458 .WSATRY_AGAIN => return error.TemporaryNameServerFailure,458 .WSANO_RECOVERY => return error.NameServerFailure,
459 .WSANO_RECOVERY => return error.NameServerFailure,459 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
460 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,460 .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
461 .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,461 .WSAHOST_NOT_FOUND => return error.UnknownHostName,
462 .WSAHOST_NOT_FOUND => return error.UnknownHostName,462 .WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
463 .WSATYPE_NOT_FOUND => return error.ServiceUnavailable,463 .WSAEINVAL => unreachable,
464 .WSAEINVAL => unreachable,464 .WSAESOCKTNOSUPPORT => unreachable,
465 .WSAESOCKTNOSUPPORT => unreachable,465 else => |err| return os.windows.unexpectedWSAError(err),
466 else => |err| return os.windows.unexpectedWSAError(err),466 } else switch (rc) {
467 };467 @intToEnum(sys.EAI, 0) => {},
468 } else {468 .ADDRFAMILY => return error.HostLacksNetworkAddresses,
469 switch (rc) {469 .AGAIN => return error.TemporaryNameServerFailure,
470 @intToEnum(sys.EAI, 0) => {},470 .BADFLAGS => unreachable, // Invalid hints
471 .ADDRFAMILY => return error.HostLacksNetworkAddresses,471 .FAIL => return error.NameServerFailure,
472 .AGAIN => return error.TemporaryNameServerFailure,472 .FAMILY => return error.AddressFamilyNotSupported,
473 .BADFLAGS => unreachable, // Invalid hints473 .MEMORY => return error.OutOfMemory,
474 .FAIL => return error.NameServerFailure,474 .NODATA => return error.HostLacksNetworkAddresses,
475 .FAMILY => return error.AddressFamilyNotSupported,475 .NONAME => return error.UnknownHostName,
476 .MEMORY => return error.OutOfMemory,476 .SERVICE => return error.ServiceUnavailable,
477 .NODATA => return error.HostLacksNetworkAddresses,477 .SOCKTYPE => unreachable, // Invalid socket type requested in hints
478 .NONAME => return error.UnknownHostName,478 .SYSTEM => switch (os.errno(-1)) {
479 .SERVICE => return error.ServiceUnavailable,479 else => |e| return os.unexpectedErrno(e),
480 .SOCKTYPE => unreachable, // Invalid socket type requested in hints480 },
481 .SYSTEM => switch (os.errno(-1)) {481 else => unreachable,
482 else => |e| return os.unexpectedErrno(e),
483 },
484 else => unreachable,
485 }
486 }482 }
487 defer sys.freeaddrinfo(res);483 defer sys.freeaddrinfo(res);
488484
lib/std/os.zig+18-5
...@@ -2447,17 +2447,29 @@ pub const SocketError = error{...@@ -2447,17 +2447,29 @@ pub const SocketError = error{
24472447
2448pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {2448pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {
2449 if (builtin.os.tag == .windows) {2449 if (builtin.os.tag == .windows) {
2450 // NOTE: cannot remove SOCK_NONBLOCK and SOCK_CLOEXEC from socket_type because2450 // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
2451 // windows does not define this flags yet2451 const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
2452 const rc = windows.ws2_32.socket(@intCast(c_int, domain), @intCast(c_int, socket_type), @intCast(c_int, protocol));2452 const flags : u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0;
2453 if (rc != windows.ws2_32.INVALID_SOCKET) return rc;2453 const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type),
2454 switch (windows.ws2_32.WSAGetLastError()) {2454 @intCast(c_int, protocol), null, 0, flags);
2455 if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) {
2455 .WSAEMFILE => return error.ProcessFdQuotaExceeded,2456 .WSAEMFILE => return error.ProcessFdQuotaExceeded,
2456 .WSAENOBUFS => return error.SystemResources,2457 .WSAENOBUFS => return error.SystemResources,
2457 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,2458 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
2458 .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,2459 .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,
2459 else => |err| return windows.unexpectedWSAError(err),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 }
24622474
2463 const have_sock_flags = comptime !std.Target.current.isDarwin();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,6 +2867,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
2855 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,2867 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
2856 else => |err| return windows.unexpectedWSAError(err),2868 else => |err| return windows.unexpectedWSAError(err),
2857 }2869 }
2870 return;
2858 }2871 }
28592872
2860 while (true) {2873 while (true) {
lib/std/os/bits/windows.zig+9
...@@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW;...@@ -221,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW;
221pub const SOCK_RDM = ws2_32.SOCK_RDM;221pub const SOCK_RDM = ws2_32.SOCK_RDM;
222pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET;222pub 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.
227pub 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.
231pub const SOCK_NONBLOCK = 0x20000;
232
224pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP;233pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP;
225pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP;234pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP;
226pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM;235pub 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,6 +174,8 @@ pub const AI_SECURE = 0x08000;
174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
175pub const AI_DISABLE_IDN_ENCODING = 0x80000;175pub const AI_DISABLE_IDN_ENCODING = 0x80000;
176176
177pub const FIONBIO = -2147195266;
178
177pub const sockaddr = extern struct {179pub const sockaddr = extern struct {
178 family: ADDRESS_FAMILY,180 family: ADDRESS_FAMILY,
179 data: [14]u8,181 data: [14]u8,
...@@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl(...@@ -724,11 +726,6 @@ pub extern "ws2_32" fn WSAIoctl(
724 lpOverlapped: ?*WSAOVERLAPPED,726 lpOverlapped: ?*WSAOVERLAPPED,
725 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,727 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
726) callconv(.Stdcall) c_int;728) callconv(.Stdcall) c_int;
727pub extern "ws2_32" fn socket(
728 af: c_int,
729 type: c_int,
730 protocol: c_int,
731) callconv(.Stdcall) SOCKET;
732pub extern "ws2_32" fn accept(729pub extern "ws2_32" fn accept(
733 s: SOCKET,730 s: SOCKET,
734 addr: ?*sockaddr,731 addr: ?*sockaddr,
...@@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo(...@@ -788,3 +785,8 @@ pub extern "ws2_32" fn getaddrinfo(
788pub extern "ws2_32" fn freeaddrinfo(785pub extern "ws2_32" fn freeaddrinfo(
789 pAddrInfo: *addrinfo,786 pAddrInfo: *addrinfo,
790) callconv(.Stdcall) void;787) callconv(.Stdcall) void;
788pub extern "ws2_32" fn ioctlsocket(
789 s: SOCKET,
790 cmd: c_long,
791 argp: *c_ulong,
792) callconv(.Stdcall) c_int;