authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-22 17:45:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-22 17:45:31-07:00
log59c26c79e809f5f8662f4f08f072c9ca6f06ac71
treee9a06ed5095edae1e9507cbd22353e181b49b566
parent79ec08fe2f06f30f1759cb1f94e3ea162309e79b
parent569f7ce49ea778864636316cfe41acb3944cf3d4

Merge branch 'BarabasGitHub-improve-windows-networking'


4 files changed, 439 insertions(+), 147 deletions(-)

lib/std/os.zig+339-142
......@@ -2646,14 +2646,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
26462646 // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
26472647 const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
26482648 const flags: u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0;
2649 const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), @intCast(c_int, protocol), null, 0, flags);
2650 if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) {
2651 .WSAEMFILE => return error.ProcessFdQuotaExceeded,
2652 .WSAENOBUFS => return error.SystemResources,
2653 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
2654 .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported,
2655 else => |err| return windows.unexpectedWSAError(err),
2656 };
2649 const rc = try windows.WSASocketW(@bitCast(i32, domain), @bitCast(i32, filtered_sock_type), @bitCast(i32, protocol), null, 0, flags);
26572650 errdefer windows.closesocket(rc) catch unreachable;
26582651 if ((socket_type & SOCK_NONBLOCK) != 0) {
26592652 var mode: c_ulong = 1; // nonblocking
......@@ -2727,28 +2720,55 @@ pub const BindError = error{
27272720
27282721 /// The socket inode would reside on a read-only filesystem.
27292722 ReadOnlyFileSystem,
2723
2724 /// The network subsystem has failed.
2725 NetworkSubsystemFailed,
2726
2727 FileDescriptorNotASocket,
2728
2729 AlreadyBound,
27302730} || UnexpectedError;
27312731
27322732/// addr is `*const T` where T is one of the sockaddr
2733pub fn bind(sockfd: fd_t, addr: *const sockaddr, len: socklen_t) BindError!void {
2734 const rc = system.bind(sockfd, addr, len);
2735 switch (errno(rc)) {
2736 0 => return,
2737 EACCES => return error.AccessDenied,
2738 EADDRINUSE => return error.AddressInUse,
2739 EBADF => unreachable, // always a race condition if this error is returned
2740 EINVAL => unreachable, // invalid parameters
2741 ENOTSOCK => unreachable, // invalid `sockfd`
2742 EADDRNOTAVAIL => return error.AddressNotAvailable,
2743 EFAULT => unreachable, // invalid `addr` pointer
2744 ELOOP => return error.SymLinkLoop,
2745 ENAMETOOLONG => return error.NameTooLong,
2746 ENOENT => return error.FileNotFound,
2747 ENOMEM => return error.SystemResources,
2748 ENOTDIR => return error.NotDir,
2749 EROFS => return error.ReadOnlyFileSystem,
2750 else => |err| return unexpectedErrno(err),
2733pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void {
2734 const rc = system.bind(sock, addr, len);
2735 if (builtin.os.tag == .windows) {
2736 if (rc == windows.ws2_32.SOCKET_ERROR) {
2737 switch (windows.ws2_32.WSAGetLastError()) {
2738 .WSANOTINITIALISED => unreachable, // not initialized WSA
2739 .WSAEACCES => return error.AccessDenied,
2740 .WSAEADDRINUSE => return error.AddressInUse,
2741 .WSAEADDRNOTAVAIL => return error.AddressNotAvailable,
2742 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
2743 .WSAEFAULT => unreachable, // invalid pointers
2744 .WSAEINVAL => return error.AlreadyBound,
2745 .WSAENOBUFS => return error.SystemResources,
2746 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2747 else => |err| return windows.unexpectedWSAError(err),
2748 }
2749 unreachable;
2750 }
2751 return;
2752 } else {
2753 switch (errno(rc)) {
2754 0 => return,
2755 EACCES => return error.AccessDenied,
2756 EADDRINUSE => return error.AddressInUse,
2757 EBADF => unreachable, // always a race condition if this error is returned
2758 EINVAL => unreachable, // invalid parameters
2759 ENOTSOCK => unreachable, // invalid `sockfd`
2760 EADDRNOTAVAIL => return error.AddressNotAvailable,
2761 EFAULT => unreachable, // invalid `addr` pointer
2762 ELOOP => return error.SymLinkLoop,
2763 ENAMETOOLONG => return error.NameTooLong,
2764 ENOENT => return error.FileNotFound,
2765 ENOMEM => return error.SystemResources,
2766 ENOTDIR => return error.NotDir,
2767 EROFS => return error.ReadOnlyFileSystem,
2768 else => |err| return unexpectedErrno(err),
2769 }
27512770 }
2771 unreachable;
27522772}
27532773
27542774const ListenError = error{
......@@ -2764,23 +2784,57 @@ const ListenError = error{
27642784
27652785 /// The socket is not of a type that supports the listen() operation.
27662786 OperationNotSupported,
2787
2788 /// The network subsystem has failed.
2789 NetworkSubsystemFailed,
2790
2791 /// Ran out of system resources
2792 /// On Windows it can either run out of socket descriptors or buffer space
2793 SystemResources,
2794
2795 /// Already connected
2796 AlreadyConnected,
2797
2798 /// Socket has not been bound yet
2799 SocketNotBound,
27672800} || UnexpectedError;
27682801
2769pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void {
2770 const rc = system.listen(sockfd, backlog);
2771 switch (errno(rc)) {
2772 0 => return,
2773 EADDRINUSE => return error.AddressInUse,
2774 EBADF => unreachable,
2775 ENOTSOCK => return error.FileDescriptorNotASocket,
2776 EOPNOTSUPP => return error.OperationNotSupported,
2777 else => |err| return unexpectedErrno(err),
2802pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
2803 const rc = system.listen(sock, backlog);
2804 if (builtin.os.tag == .windows) {
2805 if (rc == windows.ws2_32.SOCKET_ERROR) {
2806 switch (windows.ws2_32.WSAGetLastError()) {
2807 .WSANOTINITIALISED => unreachable, // not initialized WSA
2808 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2809 .WSAEADDRINUSE => return error.AddressInUse,
2810 .WSAEISCONN => return error.AlreadyConnected,
2811 .WSAEINVAL => return error.SocketNotBound,
2812 .WSAEMFILE, .WSAENOBUFS => return error.SystemResources,
2813 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
2814 .WSAEOPNOTSUPP => return error.OperationNotSupported,
2815 .WSAEINPROGRESS => unreachable,
2816 else => |err| return windows.unexpectedWSAError(err),
2817 }
2818 }
2819 return;
2820 } else {
2821 switch (errno(rc)) {
2822 0 => return,
2823 EADDRINUSE => return error.AddressInUse,
2824 EBADF => unreachable,
2825 ENOTSOCK => return error.FileDescriptorNotASocket,
2826 EOPNOTSUPP => return error.OperationNotSupported,
2827 else => |err| return unexpectedErrno(err),
2828 }
27782829 }
27792830}
27802831
27812832pub const AcceptError = error{
27822833 ConnectionAborted,
27832834
2835 /// The file descriptor sockfd does not refer to a socket.
2836 FileDescriptorNotASocket,
2837
27842838 /// The per-process limit on the number of open file descriptors has been reached.
27852839 ProcessFdQuotaExceeded,
27862840
......@@ -2806,6 +2860,16 @@ pub const AcceptError = error{
28062860 /// Permission to create a socket of the specified type and/or
28072861 /// protocol is denied.
28082862 PermissionDenied,
2863
2864 /// An incoming connection was indicated, but was subsequently terminated by the
2865 /// remote peer prior to accepting the call.
2866 ConnectionResetByPeer,
2867
2868 /// The network subsystem has failed.
2869 NetworkSubsystemFailed,
2870
2871 /// The referenced socket is not a type that supports connection-oriented service.
2872 OperationNotSupported,
28092873} || UnexpectedError;
28102874
28112875/// Accept a connection on a socket.
......@@ -2814,19 +2878,19 @@ pub const AcceptError = error{
28142878pub fn accept(
28152879 /// This argument is a socket that has been created with `socket`, bound to a local address
28162880 /// with `bind`, and is listening for connections after a `listen`.
2817 sockfd: fd_t,
2881 sock: socket_t,
28182882 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the
28192883 /// address of the peer socket, as known to the communications layer. The exact format of the
28202884 /// address returned addr is determined by the socket's address family (see `socket` and the
28212885 /// respective protocol man pages).
2822 addr: *sockaddr,
2886 addr: ?*sockaddr,
28232887 /// This argument is a value-result argument: the caller must initialize it to contain the
28242888 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
28252889 /// of the peer address.
28262890 ///
28272891 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
28282892 /// will return a value greater than was supplied to the call.
2829 addr_size: *socklen_t,
2893 addr_size: ?*socklen_t,
28302894 /// The following values can be bitwise ORed in flags to obtain different behavior:
28312895 /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`)
28322896 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
......@@ -2834,41 +2898,61 @@ pub fn accept(
28342898 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
28352899 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
28362900 flags: u32,
2837) AcceptError!fd_t {
2838 const have_accept4 = comptime !std.Target.current.isDarwin();
2901) AcceptError!socket_t {
2902 const have_accept4 = comptime !(std.Target.current.isDarwin() or builtin.os.tag == .windows);
28392903 assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s)
28402904
2841 while (true) {
2905 const accepted_sock = while (true) {
28422906 const rc = if (have_accept4)
2843 system.accept4(sockfd, addr, addr_size, flags)
2907 system.accept4(sock, addr, addr_size, flags)
28442908 else
2845 system.accept(sockfd, addr, addr_size);
2909 system.accept(sock, addr, addr_size);
28462910
2847 switch (errno(rc)) {
2848 0 => {
2849 const fd = @intCast(fd_t, rc);
2850 if (!have_accept4) {
2851 try setSockFlags(fd, flags);
2911 if (builtin.os.tag == .windows) {
2912 if (rc == windows.ws2_32.INVALID_SOCKET) {
2913 switch (windows.ws2_32.WSAGetLastError()) {
2914 .WSANOTINITIALISED => unreachable, // not initialized WSA
2915 .WSAECONNRESET => return error.ConnectionResetByPeer,
2916 .WSAEFAULT => unreachable,
2917 .WSAEINVAL => return error.SocketNotListening,
2918 .WSAEMFILE => return error.ProcessFdQuotaExceeded,
2919 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2920 .WSAENOBUFS => return error.FileDescriptorNotASocket,
2921 .WSAEOPNOTSUPP => return error.OperationNotSupported,
2922 .WSAEWOULDBLOCK => return error.WouldBlock,
2923 else => |err| return windows.unexpectedWSAError(err),
28522924 }
2853 return fd;
2854 },
2855 EINTR => continue,
2856 EAGAIN => return error.WouldBlock,
2857 EBADF => unreachable, // always a race condition
2858 ECONNABORTED => return error.ConnectionAborted,
2859 EFAULT => unreachable,
2860 EINVAL => return error.SocketNotListening,
2861 ENOTSOCK => unreachable,
2862 EMFILE => return error.ProcessFdQuotaExceeded,
2863 ENFILE => return error.SystemFdQuotaExceeded,
2864 ENOBUFS => return error.SystemResources,
2865 ENOMEM => return error.SystemResources,
2866 EOPNOTSUPP => unreachable,
2867 EPROTO => return error.ProtocolFailure,
2868 EPERM => return error.BlockedByFirewall,
2869 else => |err| return unexpectedErrno(err),
2925 } else {
2926 break rc;
2927 }
2928 } else {
2929 switch (errno(rc)) {
2930 0 => {
2931 break @intCast(socket_t, rc);
2932 },
2933 EINTR => continue,
2934 EAGAIN => return error.WouldBlock,
2935 EBADF => unreachable, // always a race condition
2936 ECONNABORTED => return error.ConnectionAborted,
2937 EFAULT => unreachable,
2938 EINVAL => return error.SocketNotListening,
2939 ENOTSOCK => unreachable,
2940 EMFILE => return error.ProcessFdQuotaExceeded,
2941 ENFILE => return error.SystemFdQuotaExceeded,
2942 ENOBUFS => return error.SystemResources,
2943 ENOMEM => return error.SystemResources,
2944 EOPNOTSUPP => unreachable,
2945 EPROTO => return error.ProtocolFailure,
2946 EPERM => return error.BlockedByFirewall,
2947 else => |err| return unexpectedErrno(err),
2948 }
28702949 }
2950 } else unreachable;
2951
2952 if (!have_accept4) {
2953 try setSockFlags(accepted_sock, flags);
28712954 }
2955 return accepted_sock;
28722956}
28732957
28742958pub const EpollCreateError = error{
......@@ -2982,18 +3066,41 @@ pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
29823066pub const GetSockNameError = error{
29833067 /// Insufficient resources were available in the system to perform the operation.
29843068 SystemResources,
3069
3070 /// The network subsystem has failed.
3071 NetworkSubsystemFailed,
3072
3073 /// Socket hasn't been bound yet
3074 SocketNotBound,
3075
3076 FileDescriptorNotASocket,
29853077} || UnexpectedError;
29863078
2987pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
2988 switch (errno(system.getsockname(sockfd, addr, addrlen))) {
2989 0 => return,
2990 else => |err| return unexpectedErrno(err),
3079pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
3080 const rc = system.getsockname(sock, addr, addrlen);
3081 if (builtin.os.tag == .windows) {
3082 if (rc == windows.ws2_32.SOCKET_ERROR) {
3083 switch (windows.ws2_32.WSAGetLastError()) {
3084 .WSANOTINITIALISED => unreachable,
3085 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3086 .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value
3087 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
3088 .WSAEINVAL => return error.SocketNotBound,
3089 else => |err| return windows.unexpectedWSAError(err),
3090 }
3091 }
3092 return;
3093 } else {
3094 switch (errno(rc)) {
3095 0 => return,
3096 else => |err| return unexpectedErrno(err),
29913097
2992 EBADF => unreachable, // always a race condition
2993 EFAULT => unreachable,
2994 EINVAL => unreachable, // invalid parameters
2995 ENOTSOCK => unreachable,
2996 ENOBUFS => return error.SystemResources,
3098 EBADF => unreachable, // always a race condition
3099 EFAULT => unreachable,
3100 EINVAL => unreachable, // invalid parameters
3101 ENOTSOCK => return error.FileDescriptorNotASocket,
3102 ENOBUFS => return error.SystemResources,
3103 }
29973104 }
29983105}
29993106
......@@ -3041,9 +3148,9 @@ pub const ConnectError = error{
30413148/// Initiate a connection on a socket.
30423149/// If `sockfd` is opened in non blocking mode, the function will
30433150/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.
3044pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
3151pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
30453152 if (builtin.os.tag == .windows) {
3046 const rc = windows.ws2_32.connect(sockfd, sock_addr, len);
3153 const rc = windows.ws2_32.connect(sock, sock_addr, @intCast(i32, len));
30473154 if (rc == 0) return;
30483155 switch (windows.ws2_32.WSAGetLastError()) {
30493156 .WSAEADDRINUSE => return error.AddressInUse,
......@@ -3066,7 +3173,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
30663173 }
30673174
30683175 while (true) {
3069 switch (errno(system.connect(sockfd, sock_addr, len))) {
3176 switch (errno(system.connect(sock, sock_addr, len))) {
30703177 0 => return,
30713178 EACCES => return error.PermissionDenied,
30723179 EPERM => return error.PermissionDenied,
......@@ -3921,32 +4028,49 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
39214028 }
39224029}
39234030
3924fn setSockFlags(fd: fd_t, flags: u32) !void {
4031fn setSockFlags(sock: socket_t, flags: u32) !void {
39254032 if ((flags & SOCK_CLOEXEC) != 0) {
3926 var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) {
3927 error.FileBusy => unreachable,
3928 error.Locked => unreachable,
3929 else => |e| return e,
3930 };
3931 fd_flags |= FD_CLOEXEC;
3932 _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) {
3933 error.FileBusy => unreachable,
3934 error.Locked => unreachable,
3935 else => |e| return e,
3936 };
4033 if (builtin.os.tag == .windows) {
4034 // TODO: Find out if this is supported for sockets
4035 } else {
4036 var fd_flags = fcntl(sock, F_GETFD, 0) catch |err| switch (err) {
4037 error.FileBusy => unreachable,
4038 error.Locked => unreachable,
4039 else => |e| return e,
4040 };
4041 fd_flags |= FD_CLOEXEC;
4042 _ = fcntl(sock, F_SETFD, fd_flags) catch |err| switch (err) {
4043 error.FileBusy => unreachable,
4044 error.Locked => unreachable,
4045 else => |e| return e,
4046 };
4047 }
39374048 }
39384049 if ((flags & SOCK_NONBLOCK) != 0) {
3939 var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) {
3940 error.FileBusy => unreachable,
3941 error.Locked => unreachable,
3942 else => |e| return e,
3943 };
3944 fl_flags |= O_NONBLOCK;
3945 _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) {
3946 error.FileBusy => unreachable,
3947 error.Locked => unreachable,
3948 else => |e| return e,
3949 };
4050 if (builtin.os.tag == .windows) {
4051 var mode: c_ulong = 1;
4052 if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) {
4053 switch (windows.ws2_32.WSAGetLastError()) {
4054 .WSANOTINITIALISED => unreachable,
4055 .WSAENETDOWN => return error.NetworkSubsystemFailed,
4056 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
4057 // TODO: handle more errors
4058 else => |err| return windows.unexpectedWSAError(err),
4059 }
4060 }
4061 } else {
4062 var fl_flags = fcntl(sock, F_GETFL, 0) catch |err| switch (err) {
4063 error.FileBusy => unreachable,
4064 error.Locked => unreachable,
4065 else => |e| return e,
4066 };
4067 fl_flags |= O_NONBLOCK;
4068 _ = fcntl(sock, F_SETFL, fl_flags) catch |err| switch (err) {
4069 error.FileBusy => unreachable,
4070 error.Locked => unreachable,
4071 else => |e| return e,
4072 };
4073 }
39504074 }
39514075}
39524076
......@@ -4544,6 +4668,8 @@ pub const SendError = error{
45444668 /// The local end has been shut down on a connection oriented socket. In this case, the
45454669 /// process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
45464670 BrokenPipe,
4671
4672 FileDescriptorNotASocket,
45474673} || UnexpectedError;
45484674
45494675/// Transmit a message to another socket.
......@@ -4573,7 +4699,7 @@ pub const SendError = error{
45734699/// possible to send more data.
45744700pub fn sendto(
45754701 /// The file descriptor of the sending socket.
4576 sockfd: fd_t,
4702 sockfd: socket_t,
45774703 /// Message to send.
45784704 buf: []const u8,
45794705 flags: u32,
......@@ -4582,26 +4708,43 @@ pub fn sendto(
45824708) SendError!usize {
45834709 while (true) {
45844710 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
4585 switch (errno(rc)) {
4586 0 => return @intCast(usize, rc),
4587 EACCES => return error.AccessDenied,
4588 EAGAIN => return error.WouldBlock,
4589 EALREADY => return error.FastOpenAlreadyInProgress,
4590 EBADF => unreachable, // always a race condition
4591 ECONNRESET => return error.ConnectionResetByPeer,
4592 EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
4593 EFAULT => unreachable, // An invalid user space address was specified for an argument.
4594 EINTR => continue,
4595 EINVAL => unreachable, // Invalid argument passed.
4596 EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
4597 EMSGSIZE => return error.MessageTooBig,
4598 ENOBUFS => return error.SystemResources,
4599 ENOMEM => return error.SystemResources,
4600 ENOTCONN => unreachable, // The socket is not connected, and no target has been given.
4601 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
4602 EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
4603 EPIPE => return error.BrokenPipe,
4604 else => |err| return unexpectedErrno(err),
4711 if (builtin.os.tag == .windows) {
4712 if (rc == windows.ws2_32.SOCKET_ERROR) {
4713 switch (windows.ws2_32.WSAGetLastError()) {
4714 .WSAEACCES => return error.AccessDenied,
4715 .WSAECONNRESET => return error.ConnectionResetByPeer,
4716 .WSAEMSGSIZE => return error.MessageTooBig,
4717 .WSAENOBUFS => return error.SystemResources,
4718 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
4719 // TODO: handle more errors
4720 else => |err| return windows.unexpectedWSAError(err),
4721 }
4722 } else {
4723 return @intCast(usize, rc);
4724 }
4725 } else {
4726 switch (errno(rc)) {
4727 0 => return @intCast(usize, rc),
4728
4729 EACCES => return error.AccessDenied,
4730 EAGAIN => return error.WouldBlock,
4731 EALREADY => return error.FastOpenAlreadyInProgress,
4732 EBADF => unreachable, // always a race condition
4733 ECONNRESET => return error.ConnectionResetByPeer,
4734 EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
4735 EFAULT => unreachable, // An invalid user space address was specified for an argument.
4736 EINTR => continue,
4737 EINVAL => unreachable, // Invalid argument passed.
4738 EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
4739 EMSGSIZE => return error.MessageTooBig,
4740 ENOBUFS => return error.SystemResources,
4741 ENOMEM => return error.SystemResources,
4742 ENOTCONN => unreachable, // The socket is not connected, and no target has been given.
4743 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
4744 EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
4745 EPIPE => return error.BrokenPipe,
4746 else => |err| return unexpectedErrno(err),
4747 }
46054748 }
46064749 }
46074750}
......@@ -4627,7 +4770,7 @@ pub fn sendto(
46274770/// possible to send more data.
46284771pub fn send(
46294772 /// The file descriptor of the sending socket.
4630 sockfd: fd_t,
4773 sockfd: socket_t,
46314774 buf: []const u8,
46324775 flags: u32,
46334776) SendError!usize {
......@@ -5042,6 +5185,9 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
50425185}
50435186
50445187pub const PollError = error{
5188 /// The network subsystem has failed.
5189 NetworkSubsystemFailed,
5190
50455191 /// The kernel had no space to allocate file descriptor tables.
50465192 SystemResources,
50475193} || UnexpectedError;
......@@ -5049,14 +5195,29 @@ pub const PollError = error{
50495195pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {
50505196 while (true) {
50515197 const rc = system.poll(fds.ptr, fds.len, timeout);
5052 switch (errno(rc)) {
5053 0 => return @intCast(usize, rc),
5054 EFAULT => unreachable,
5055 EINTR => continue,
5056 EINVAL => unreachable,
5057 ENOMEM => return error.SystemResources,
5058 else => |err| return unexpectedErrno(err),
5198 if (builtin.os.tag == .windows) {
5199 if (rc == windows.ws2_32.SOCKET_ERROR) {
5200 switch (windows.ws2_32.WSAGetLastError()) {
5201 .WSANOTINITIALISED => unreachable,
5202 .WSAENETDOWN => return error.NetworkSubsystemFailed,
5203 .WSAENOBUFS => return error.SystemResources,
5204 // TODO: handle more errors
5205 else => |err| return windows.unexpectedWSAError(err),
5206 }
5207 } else {
5208 return @intCast(usize, rc);
5209 }
5210 } else {
5211 switch (errno(rc)) {
5212 0 => return @intCast(usize, rc),
5213 EFAULT => unreachable,
5214 EINTR => continue,
5215 EINVAL => unreachable,
5216 ENOMEM => return error.SystemResources,
5217 else => |err| return unexpectedErrno(err),
5218 }
50595219 }
5220 unreachable;
50605221 }
50615222}
50625223
......@@ -5071,12 +5232,30 @@ pub const RecvFromError = error{
50715232
50725233 /// Could not allocate kernel memory.
50735234 SystemResources,
5235
5236 ConnectionResetByPeer,
5237
5238 /// The socket has not been bound.
5239 SocketNotBound,
5240
5241 /// The UDP message was too big for the buffer and part of it has been discarded
5242 MessageTooBig,
5243
5244 /// The network subsystem has failed.
5245 NetworkSubsystemFailed,
5246
5247 /// The socket is not connected (connection-oriented sockets only).
5248 SocketNotConnected,
50745249} || UnexpectedError;
50755250
5251pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {
5252 return recvfrom(sock, buf, flags, null, null);
5253}
5254
50765255/// If `sockfd` is opened in non blocking mode, the function will
50775256/// return error.WouldBlock when EAGAIN is received.
50785257pub fn recvfrom(
5079 sockfd: fd_t,
5258 sockfd: socket_t,
50805259 buf: []u8,
50815260 flags: u32,
50825261 src_addr: ?*sockaddr,
......@@ -5084,18 +5263,36 @@ pub fn recvfrom(
50845263) RecvFromError!usize {
50855264 while (true) {
50865265 const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);
5087 switch (errno(rc)) {
5088 0 => return @intCast(usize, rc),
5089 EBADF => unreachable, // always a race condition
5090 EFAULT => unreachable,
5091 EINVAL => unreachable,
5092 ENOTCONN => unreachable,
5093 ENOTSOCK => unreachable,
5094 EINTR => continue,
5095 EAGAIN => return error.WouldBlock,
5096 ENOMEM => return error.SystemResources,
5097 ECONNREFUSED => return error.ConnectionRefused,
5098 else => |err| return unexpectedErrno(err),
5266 if (builtin.os.tag == .windows) {
5267 if (rc == windows.ws2_32.SOCKET_ERROR) {
5268 switch (windows.ws2_32.WSAGetLastError()) {
5269 .WSANOTINITIALISED => unreachable,
5270 .WSAECONNRESET => return error.ConnectionResetByPeer,
5271 .WSAEINVAL => return error.SocketNotBound,
5272 .WSAEMSGSIZE => return error.MessageTooBig,
5273 .WSAENETDOWN => return error.NetworkSubsystemFailed,
5274 .WSAENOTCONN => return error.SocketNotConnected,
5275 .WSAEWOULDBLOCK => return error.WouldBlock,
5276 // TODO: handle more errors
5277 else => |err| return windows.unexpectedWSAError(err),
5278 }
5279 } else {
5280 return @intCast(usize, rc);
5281 }
5282 } else {
5283 switch (errno(rc)) {
5284 0 => return @intCast(usize, rc),
5285 EBADF => unreachable, // always a race condition
5286 EFAULT => unreachable,
5287 EINVAL => unreachable,
5288 ENOTCONN => unreachable,
5289 ENOTSOCK => unreachable,
5290 EINTR => continue,
5291 EAGAIN => return error.WouldBlock,
5292 ENOMEM => return error.SystemResources,
5293 ECONNREFUSED => return error.ConnectionRefused,
5294 else => |err| return unexpectedErrno(err),
5295 }
50995296 }
51005297 }
51015298}
lib/std/os/bits/windows.zig+14-1
......@@ -172,7 +172,7 @@ pub const AT_REMOVEDIR = 0x200;
172172
173173pub const in_port_t = u16;
174174pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
175pub const socklen_t = u32;
175pub const socklen_t = ws2_32.socklen_t;
176176
177177pub const sockaddr = ws2_32.sockaddr;
178178pub const sockaddr_in = ws2_32.sockaddr_in;
......@@ -243,6 +243,19 @@ pub const IPPROTO_UDP = ws2_32.IPPROTO_UDP;
243243pub const IPPROTO_ICMPV6 = ws2_32.IPPROTO_ICMPV6;
244244pub const IPPROTO_RM = ws2_32.IPPROTO_RM;
245245
246pub const pollfd = ws2_32.pollfd;
247
248pub const POLLRDNORM = ws2_32.POLLRDNORM;
249pub const POLLRDBAND = ws2_32.POLLRDBAND;
250pub const POLLIN = ws2_32.POLLIN;
251pub const POLLPRI = ws2_32.POLLPRI;
252pub const POLLWRNORM = ws2_32.POLLWRNORM;
253pub const POLLOUT = ws2_32.POLLOUT;
254pub const POLLWRBAND = ws2_32.POLLWRBAND;
255pub const POLLERR = ws2_32.POLLERR;
256pub const POLLHUP = ws2_32.POLLHUP;
257pub const POLLNVAL = ws2_32.POLLNVAL;
258
246259pub const O_RDONLY = 0o0;
247260pub const O_WRONLY = 0o1;
248261pub const O_RDWR = 0o2;
lib/std/os/windows.zig+42
......@@ -1157,6 +1157,14 @@ pub fn WSASocketW(
11571157 return rc;
11581158}
11591159
1160pub fn bind(s: ws2_32.SOCKET, name: *const ws2_32.sockaddr, namelen: ws2_32.socklen_t) i32 {
1161 return ws2_32.bind(s, name, @intCast(i32, namelen));
1162}
1163
1164pub fn listen(s: ws2_32.SOCKET, backlog: u31) i32 {
1165 return ws2_32.listen(s, backlog);
1166}
1167
11601168pub fn closesocket(s: ws2_32.SOCKET) !void {
11611169 switch (ws2_32.closesocket(s)) {
11621170 0 => {},
......@@ -1167,6 +1175,40 @@ pub fn closesocket(s: ws2_32.SOCKET) !void {
11671175 }
11681176}
11691177
1178pub fn accept(s: ws2_32.SOCKET, name: ?*ws2_32.sockaddr, namelen: ?*ws2_32.socklen_t) ws2_32.SOCKET {
1179 assert((name == null) == (namelen == null));
1180 return ws2_32.accept(s, name, @ptrCast(?*i32, namelen));
1181}
1182
1183pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
1184 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));
1185}
1186
1187pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
1188 var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) };
1189 var bytes_send: DWORD = undefined;
1190 if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, @intCast(i32, to_len), null, null) == ws2_32.SOCKET_ERROR) {
1191 return ws2_32.SOCKET_ERROR;
1192 } else {
1193 return @as(i32, @intCast(u31, bytes_send));
1194 }
1195}
1196
1197pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 {
1198 var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = buf };
1199 var bytes_received: DWORD = undefined;
1200 var flags_inout = flags;
1201 if (ws2_32.WSARecvFrom(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_received, &flags_inout, from, from_len, null, null) == ws2_32.SOCKET_ERROR) {
1202 return ws2_32.SOCKET_ERROR;
1203 } else {
1204 return @as(i32, @intCast(u31, bytes_received));
1205 }
1206}
1207
1208pub fn poll(fds: [*]ws2_32.pollfd, n: usize, timeout: i32) i32 {
1209 return ws2_32.WSAPoll(fds, @intCast(u32, n), timeout);
1210}
1211
11701212pub fn WSAIoctl(
11711213 s: ws2_32.SOCKET,
11721214 dwIoControlCode: DWORD,
lib/std/os/windows/ws2_32.zig+44-4
......@@ -116,7 +116,7 @@ pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred:
116116pub const ADDRESS_FAMILY = u16;
117117
118118// Microsoft use the signed c_int for this, but it should never be negative
119const socklen_t = u32;
119pub const socklen_t = u32;
120120
121121pub const AF_UNSPEC = 0;
122122pub const AF_UNIX = 1;
......@@ -234,6 +234,27 @@ pub const WSAMSG = extern struct {
234234 dwFlags: DWORD,
235235};
236236
237pub const pollfd = extern struct {
238 fd: SOCKET,
239 events: SHORT,
240 revents: SHORT,
241};
242
243// Event flag definitions for WSAPoll().
244
245pub const POLLRDNORM = 0x0100;
246pub const POLLRDBAND = 0x0200;
247pub const POLLIN = (POLLRDNORM | POLLRDBAND);
248pub const POLLPRI = 0x0400;
249
250pub const POLLWRNORM = 0x0010;
251pub const POLLOUT = (POLLWRNORM);
252pub const POLLWRBAND = 0x0020;
253
254pub const POLLERR = 0x0001;
255pub const POLLHUP = 0x0002;
256pub const POLLNVAL = 0x0004;
257
237258// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2
238259pub const WinsockError = extern enum(u16) {
239260 /// Specified event object handle is invalid.
......@@ -734,12 +755,21 @@ pub extern "ws2_32" fn WSAIoctl(
734755pub extern "ws2_32" fn accept(
735756 s: SOCKET,
736757 addr: ?*sockaddr,
737 addrlen: socklen_t,
758 addrlen: ?*c_int,
738759) callconv(.Stdcall) SOCKET;
760pub extern "ws2_32" fn bind(
761 s: SOCKET,
762 addr: ?*const sockaddr,
763 addrlen: c_int,
764) callconv(.Stdcall) c_int;
739765pub extern "ws2_32" fn connect(
740766 s: SOCKET,
741767 name: *const sockaddr,
742 namelen: socklen_t,
768 namelen: c_int,
769) callconv(.Stdcall) c_int;
770pub extern "ws2_32" fn listen(
771 s: SOCKET,
772 backlog: c_int,
743773) callconv(.Stdcall) c_int;
744774pub extern "ws2_32" fn WSARecv(
745775 s: SOCKET,
......@@ -777,10 +807,15 @@ pub extern "ws2_32" fn WSASendTo(
777807 lpNumberOfBytesSent: ?*DWORD,
778808 dwFlags: DWORD,
779809 lpTo: ?*const sockaddr,
780 iTolen: socklen_t,
810 iTolen: c_int,
781811 lpOverlapped: ?*WSAOVERLAPPED,
782812 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
783813) callconv(.Stdcall) c_int;
814pub extern "ws2_32" fn WSAPoll(
815 fdArray: [*]pollfd,
816 fds: c_ulong,
817 timeout: c_int,
818) callconv(.Stdcall) c_int;
784819pub extern "ws2_32" fn getaddrinfo(
785820 pNodeName: [*:0]const u8,
786821 pServiceName: [*:0]const u8,
......@@ -795,3 +830,8 @@ pub extern "ws2_32" fn ioctlsocket(
795830 cmd: c_long,
796831 argp: *c_ulong,
797832) callconv(.Stdcall) c_int;
833pub extern "ws2_32" fn getsockname(
834 s: SOCKET,
835 name: *sockaddr,
836 namelen: *c_int,
837) callconv(.Stdcall) c_int;