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...@@ -2646,14 +2646,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
2646 // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations2646 // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
2647 const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);2647 const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
2648 const flags: u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0;2648 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);2649 const rc = try windows.WSASocketW(@bitCast(i32, domain), @bitCast(i32, filtered_sock_type), @bitCast(i32, 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 };
2657 errdefer windows.closesocket(rc) catch unreachable;2650 errdefer windows.closesocket(rc) catch unreachable;
2658 if ((socket_type & SOCK_NONBLOCK) != 0) {2651 if ((socket_type & SOCK_NONBLOCK) != 0) {
2659 var mode: c_ulong = 1; // nonblocking2652 var mode: c_ulong = 1; // nonblocking
...@@ -2727,28 +2720,55 @@ pub const BindError = error{...@@ -2727,28 +2720,55 @@ pub const BindError = error{
27272720
2728 /// The socket inode would reside on a read-only filesystem.2721 /// The socket inode would reside on a read-only filesystem.
2729 ReadOnlyFileSystem,2722 ReadOnlyFileSystem,
2723
2724 /// The network subsystem has failed.
2725 NetworkSubsystemFailed,
2726
2727 FileDescriptorNotASocket,
2728
2729 AlreadyBound,
2730} || UnexpectedError;2730} || UnexpectedError;
27312731
2732/// addr is `*const T` where T is one of the sockaddr2732/// 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 {2733pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void {
2734 const rc = system.bind(sockfd, addr, len);2734 const rc = system.bind(sock, addr, len);
2735 switch (errno(rc)) {2735 if (builtin.os.tag == .windows) {
2736 0 => return,2736 if (rc == windows.ws2_32.SOCKET_ERROR) {
2737 EACCES => return error.AccessDenied,2737 switch (windows.ws2_32.WSAGetLastError()) {
2738 EADDRINUSE => return error.AddressInUse,2738 .WSANOTINITIALISED => unreachable, // not initialized WSA
2739 EBADF => unreachable, // always a race condition if this error is returned2739 .WSAEACCES => return error.AccessDenied,
2740 EINVAL => unreachable, // invalid parameters2740 .WSAEADDRINUSE => return error.AddressInUse,
2741 ENOTSOCK => unreachable, // invalid `sockfd`2741 .WSAEADDRNOTAVAIL => return error.AddressNotAvailable,
2742 EADDRNOTAVAIL => return error.AddressNotAvailable,2742 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
2743 EFAULT => unreachable, // invalid `addr` pointer2743 .WSAEFAULT => unreachable, // invalid pointers
2744 ELOOP => return error.SymLinkLoop,2744 .WSAEINVAL => return error.AlreadyBound,
2745 ENAMETOOLONG => return error.NameTooLong,2745 .WSAENOBUFS => return error.SystemResources,
2746 ENOENT => return error.FileNotFound,2746 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2747 ENOMEM => return error.SystemResources,2747 else => |err| return windows.unexpectedWSAError(err),
2748 ENOTDIR => return error.NotDir,2748 }
2749 EROFS => return error.ReadOnlyFileSystem,2749 unreachable;
2750 else => |err| return unexpectedErrno(err),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 }
2751 }2770 }
2771 unreachable;
2752}2772}
27532773
2754const ListenError = error{2774const ListenError = error{
...@@ -2764,23 +2784,57 @@ const ListenError = error{...@@ -2764,23 +2784,57 @@ const ListenError = error{
27642784
2765 /// The socket is not of a type that supports the listen() operation.2785 /// The socket is not of a type that supports the listen() operation.
2766 OperationNotSupported,2786 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,
2767} || UnexpectedError;2800} || UnexpectedError;
27682801
2769pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void {2802pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
2770 const rc = system.listen(sockfd, backlog);2803 const rc = system.listen(sock, backlog);
2771 switch (errno(rc)) {2804 if (builtin.os.tag == .windows) {
2772 0 => return,2805 if (rc == windows.ws2_32.SOCKET_ERROR) {
2773 EADDRINUSE => return error.AddressInUse,2806 switch (windows.ws2_32.WSAGetLastError()) {
2774 EBADF => unreachable,2807 .WSANOTINITIALISED => unreachable, // not initialized WSA
2775 ENOTSOCK => return error.FileDescriptorNotASocket,2808 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2776 EOPNOTSUPP => return error.OperationNotSupported,2809 .WSAEADDRINUSE => return error.AddressInUse,
2777 else => |err| return unexpectedErrno(err),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 }
2778 }2829 }
2779}2830}
27802831
2781pub const AcceptError = error{2832pub const AcceptError = error{
2782 ConnectionAborted,2833 ConnectionAborted,
27832834
2835 /// The file descriptor sockfd does not refer to a socket.
2836 FileDescriptorNotASocket,
2837
2784 /// The per-process limit on the number of open file descriptors has been reached.2838 /// The per-process limit on the number of open file descriptors has been reached.
2785 ProcessFdQuotaExceeded,2839 ProcessFdQuotaExceeded,
27862840
...@@ -2806,6 +2860,16 @@ pub const AcceptError = error{...@@ -2806,6 +2860,16 @@ pub const AcceptError = error{
2806 /// Permission to create a socket of the specified type and/or2860 /// Permission to create a socket of the specified type and/or
2807 /// protocol is denied.2861 /// protocol is denied.
2808 PermissionDenied,2862 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,
2809} || UnexpectedError;2873} || UnexpectedError;
28102874
2811/// Accept a connection on a socket.2875/// Accept a connection on a socket.
...@@ -2814,19 +2878,19 @@ pub const AcceptError = error{...@@ -2814,19 +2878,19 @@ pub const AcceptError = error{
2814pub fn accept(2878pub fn accept(
2815 /// This argument is a socket that has been created with `socket`, bound to a local address2879 /// This argument is a socket that has been created with `socket`, bound to a local address
2816 /// with `bind`, and is listening for connections after a `listen`.2880 /// with `bind`, and is listening for connections after a `listen`.
2817 sockfd: fd_t,2881 sock: socket_t,
2818 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the2882 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the
2819 /// address of the peer socket, as known to the communications layer. The exact format of the2883 /// address of the peer socket, as known to the communications layer. The exact format of the
2820 /// address returned addr is determined by the socket's address family (see `socket` and the2884 /// address returned addr is determined by the socket's address family (see `socket` and the
2821 /// respective protocol man pages).2885 /// respective protocol man pages).
2822 addr: *sockaddr,2886 addr: ?*sockaddr,
2823 /// This argument is a value-result argument: the caller must initialize it to contain the2887 /// This argument is a value-result argument: the caller must initialize it to contain the
2824 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size2888 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
2825 /// of the peer address.2889 /// of the peer address.
2826 ///2890 ///
2827 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`2891 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
2828 /// will return a value greater than was supplied to the call.2892 /// will return a value greater than was supplied to the call.
2829 addr_size: *socklen_t,2893 addr_size: ?*socklen_t,
2830 /// The following values can be bitwise ORed in flags to obtain different behavior:2894 /// The following values can be bitwise ORed in flags to obtain different behavior:
2831 /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`)2895 /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`)
2832 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve2896 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
...@@ -2834,41 +2898,61 @@ pub fn accept(...@@ -2834,41 +2898,61 @@ pub fn accept(
2834 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the2898 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
2835 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.2899 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
2836 flags: u32,2900 flags: u32,
2837) AcceptError!fd_t {2901) AcceptError!socket_t {
2838 const have_accept4 = comptime !std.Target.current.isDarwin();2902 const have_accept4 = comptime !(std.Target.current.isDarwin() or builtin.os.tag == .windows);
2839 assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s)2903 assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s)
28402904
2841 while (true) {2905 const accepted_sock = while (true) {
2842 const rc = if (have_accept4)2906 const rc = if (have_accept4)
2843 system.accept4(sockfd, addr, addr_size, flags)2907 system.accept4(sock, addr, addr_size, flags)
2844 else2908 else
2845 system.accept(sockfd, addr, addr_size);2909 system.accept(sock, addr, addr_size);
28462910
2847 switch (errno(rc)) {2911 if (builtin.os.tag == .windows) {
2848 0 => {2912 if (rc == windows.ws2_32.INVALID_SOCKET) {
2849 const fd = @intCast(fd_t, rc);2913 switch (windows.ws2_32.WSAGetLastError()) {
2850 if (!have_accept4) {2914 .WSANOTINITIALISED => unreachable, // not initialized WSA
2851 try setSockFlags(fd, flags);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),
2852 }2924 }
2853 return fd;2925 } else {
2854 },2926 break rc;
2855 EINTR => continue,2927 }
2856 EAGAIN => return error.WouldBlock,2928 } else {
2857 EBADF => unreachable, // always a race condition2929 switch (errno(rc)) {
2858 ECONNABORTED => return error.ConnectionAborted,2930 0 => {
2859 EFAULT => unreachable,2931 break @intCast(socket_t, rc);
2860 EINVAL => return error.SocketNotListening,2932 },
2861 ENOTSOCK => unreachable,2933 EINTR => continue,
2862 EMFILE => return error.ProcessFdQuotaExceeded,2934 EAGAIN => return error.WouldBlock,
2863 ENFILE => return error.SystemFdQuotaExceeded,2935 EBADF => unreachable, // always a race condition
2864 ENOBUFS => return error.SystemResources,2936 ECONNABORTED => return error.ConnectionAborted,
2865 ENOMEM => return error.SystemResources,2937 EFAULT => unreachable,
2866 EOPNOTSUPP => unreachable,2938 EINVAL => return error.SocketNotListening,
2867 EPROTO => return error.ProtocolFailure,2939 ENOTSOCK => unreachable,
2868 EPERM => return error.BlockedByFirewall,2940 EMFILE => return error.ProcessFdQuotaExceeded,
2869 else => |err| return unexpectedErrno(err),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 }
2870 }2949 }
2950 } else unreachable;
2951
2952 if (!have_accept4) {
2953 try setSockFlags(accepted_sock, flags);
2871 }2954 }
2955 return accepted_sock;
2872}2956}
28732957
2874pub const EpollCreateError = error{2958pub const EpollCreateError = error{
...@@ -2982,18 +3066,41 @@ pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {...@@ -2982,18 +3066,41 @@ pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
2982pub const GetSockNameError = error{3066pub const GetSockNameError = error{
2983 /// Insufficient resources were available in the system to perform the operation.3067 /// Insufficient resources were available in the system to perform the operation.
2984 SystemResources,3068 SystemResources,
3069
3070 /// The network subsystem has failed.
3071 NetworkSubsystemFailed,
3072
3073 /// Socket hasn't been bound yet
3074 SocketNotBound,
3075
3076 FileDescriptorNotASocket,
2985} || UnexpectedError;3077} || UnexpectedError;
29863078
2987pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {3079pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
2988 switch (errno(system.getsockname(sockfd, addr, addrlen))) {3080 const rc = system.getsockname(sock, addr, addrlen);
2989 0 => return,3081 if (builtin.os.tag == .windows) {
2990 else => |err| return unexpectedErrno(err),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 condition3098 EBADF => unreachable, // always a race condition
2993 EFAULT => unreachable,3099 EFAULT => unreachable,
2994 EINVAL => unreachable, // invalid parameters3100 EINVAL => unreachable, // invalid parameters
2995 ENOTSOCK => unreachable,3101 ENOTSOCK => return error.FileDescriptorNotASocket,
2996 ENOBUFS => return error.SystemResources,3102 ENOBUFS => return error.SystemResources,
3103 }
2997 }3104 }
2998}3105}
29993106
...@@ -3041,9 +3148,9 @@ pub const ConnectError = error{...@@ -3041,9 +3148,9 @@ pub const ConnectError = error{
3041/// Initiate a connection on a socket.3148/// Initiate a connection on a socket.
3042/// If `sockfd` is opened in non blocking mode, the function will3149/// If `sockfd` is opened in non blocking mode, the function will
3043/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.3150/// 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 {
3045 if (builtin.os.tag == .windows) {3152 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));
3047 if (rc == 0) return;3154 if (rc == 0) return;
3048 switch (windows.ws2_32.WSAGetLastError()) {3155 switch (windows.ws2_32.WSAGetLastError()) {
3049 .WSAEADDRINUSE => return error.AddressInUse,3156 .WSAEADDRINUSE => return error.AddressInUse,
...@@ -3066,7 +3173,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con...@@ -3066,7 +3173,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
3066 }3173 }
30673174
3068 while (true) {3175 while (true) {
3069 switch (errno(system.connect(sockfd, sock_addr, len))) {3176 switch (errno(system.connect(sock, sock_addr, len))) {
3070 0 => return,3177 0 => return,
3071 EACCES => return error.PermissionDenied,3178 EACCES => return error.PermissionDenied,
3072 EPERM => return error.PermissionDenied,3179 EPERM => return error.PermissionDenied,
...@@ -3921,32 +4028,49 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {...@@ -3921,32 +4028,49 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
3921 }4028 }
3922}4029}
39234030
3924fn setSockFlags(fd: fd_t, flags: u32) !void {4031fn setSockFlags(sock: socket_t, flags: u32) !void {
3925 if ((flags & SOCK_CLOEXEC) != 0) {4032 if ((flags & SOCK_CLOEXEC) != 0) {
3926 var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) {4033 if (builtin.os.tag == .windows) {
3927 error.FileBusy => unreachable,4034 // TODO: Find out if this is supported for sockets
3928 error.Locked => unreachable,4035 } else {
3929 else => |e| return e,4036 var fd_flags = fcntl(sock, F_GETFD, 0) catch |err| switch (err) {
3930 };4037 error.FileBusy => unreachable,
3931 fd_flags |= FD_CLOEXEC;4038 error.Locked => unreachable,
3932 _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) {4039 else => |e| return e,
3933 error.FileBusy => unreachable,4040 };
3934 error.Locked => unreachable,4041 fd_flags |= FD_CLOEXEC;
3935 else => |e| return e,4042 _ = fcntl(sock, F_SETFD, fd_flags) catch |err| switch (err) {
3936 };4043 error.FileBusy => unreachable,
4044 error.Locked => unreachable,
4045 else => |e| return e,
4046 };
4047 }
3937 }4048 }
3938 if ((flags & SOCK_NONBLOCK) != 0) {4049 if ((flags & SOCK_NONBLOCK) != 0) {
3939 var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) {4050 if (builtin.os.tag == .windows) {
3940 error.FileBusy => unreachable,4051 var mode: c_ulong = 1;
3941 error.Locked => unreachable,4052 if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) {
3942 else => |e| return e,4053 switch (windows.ws2_32.WSAGetLastError()) {
3943 };4054 .WSANOTINITIALISED => unreachable,
3944 fl_flags |= O_NONBLOCK;4055 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3945 _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) {4056 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
3946 error.FileBusy => unreachable,4057 // TODO: handle more errors
3947 error.Locked => unreachable,4058 else => |err| return windows.unexpectedWSAError(err),
3948 else => |e| return e,4059 }
3949 };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 }
3950 }4074 }
3951}4075}
39524076
...@@ -4544,6 +4668,8 @@ pub const SendError = error{...@@ -4544,6 +4668,8 @@ pub const SendError = error{
4544 /// The local end has been shut down on a connection oriented socket. In this case, the4668 /// The local end has been shut down on a connection oriented socket. In this case, the
4545 /// process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.4669 /// process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
4546 BrokenPipe,4670 BrokenPipe,
4671
4672 FileDescriptorNotASocket,
4547} || UnexpectedError;4673} || UnexpectedError;
45484674
4549/// Transmit a message to another socket.4675/// Transmit a message to another socket.
...@@ -4573,7 +4699,7 @@ pub const SendError = error{...@@ -4573,7 +4699,7 @@ pub const SendError = error{
4573/// possible to send more data.4699/// possible to send more data.
4574pub fn sendto(4700pub fn sendto(
4575 /// The file descriptor of the sending socket.4701 /// The file descriptor of the sending socket.
4576 sockfd: fd_t,4702 sockfd: socket_t,
4577 /// Message to send.4703 /// Message to send.
4578 buf: []const u8,4704 buf: []const u8,
4579 flags: u32,4705 flags: u32,
...@@ -4582,26 +4708,43 @@ pub fn sendto(...@@ -4582,26 +4708,43 @@ pub fn sendto(
4582) SendError!usize {4708) SendError!usize {
4583 while (true) {4709 while (true) {
4584 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);4710 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
4585 switch (errno(rc)) {4711 if (builtin.os.tag == .windows) {
4586 0 => return @intCast(usize, rc),4712 if (rc == windows.ws2_32.SOCKET_ERROR) {
4587 EACCES => return error.AccessDenied,4713 switch (windows.ws2_32.WSAGetLastError()) {
4588 EAGAIN => return error.WouldBlock,4714 .WSAEACCES => return error.AccessDenied,
4589 EALREADY => return error.FastOpenAlreadyInProgress,4715 .WSAECONNRESET => return error.ConnectionResetByPeer,
4590 EBADF => unreachable, // always a race condition4716 .WSAEMSGSIZE => return error.MessageTooBig,
4591 ECONNRESET => return error.ConnectionResetByPeer,4717 .WSAENOBUFS => return error.SystemResources,
4592 EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.4718 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
4593 EFAULT => unreachable, // An invalid user space address was specified for an argument.4719 // TODO: handle more errors
4594 EINTR => continue,4720 else => |err| return windows.unexpectedWSAError(err),
4595 EINVAL => unreachable, // Invalid argument passed.4721 }
4596 EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified4722 } else {
4597 EMSGSIZE => return error.MessageTooBig,4723 return @intCast(usize, rc);
4598 ENOBUFS => return error.SystemResources,4724 }
4599 ENOMEM => return error.SystemResources,4725 } else {
4600 ENOTCONN => unreachable, // The socket is not connected, and no target has been given.4726 switch (errno(rc)) {
4601 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.4727 0 => return @intCast(usize, rc),
4602 EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.4728
4603 EPIPE => return error.BrokenPipe,4729 EACCES => return error.AccessDenied,
4604 else => |err| return unexpectedErrno(err),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 }
4605 }4748 }
4606 }4749 }
4607}4750}
...@@ -4627,7 +4770,7 @@ pub fn sendto(...@@ -4627,7 +4770,7 @@ pub fn sendto(
4627/// possible to send more data.4770/// possible to send more data.
4628pub fn send(4771pub fn send(
4629 /// The file descriptor of the sending socket.4772 /// The file descriptor of the sending socket.
4630 sockfd: fd_t,4773 sockfd: socket_t,
4631 buf: []const u8,4774 buf: []const u8,
4632 flags: u32,4775 flags: u32,
4633) SendError!usize {4776) 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...@@ -5042,6 +5185,9 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
5042}5185}
50435186
5044pub const PollError = error{5187pub const PollError = error{
5188 /// The network subsystem has failed.
5189 NetworkSubsystemFailed,
5190
5045 /// The kernel had no space to allocate file descriptor tables.5191 /// The kernel had no space to allocate file descriptor tables.
5046 SystemResources,5192 SystemResources,
5047} || UnexpectedError;5193} || UnexpectedError;
...@@ -5049,14 +5195,29 @@ pub const PollError = error{...@@ -5049,14 +5195,29 @@ pub const PollError = error{
5049pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {5195pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {
5050 while (true) {5196 while (true) {
5051 const rc = system.poll(fds.ptr, fds.len, timeout);5197 const rc = system.poll(fds.ptr, fds.len, timeout);
5052 switch (errno(rc)) {5198 if (builtin.os.tag == .windows) {
5053 0 => return @intCast(usize, rc),5199 if (rc == windows.ws2_32.SOCKET_ERROR) {
5054 EFAULT => unreachable,5200 switch (windows.ws2_32.WSAGetLastError()) {
5055 EINTR => continue,5201 .WSANOTINITIALISED => unreachable,
5056 EINVAL => unreachable,5202 .WSAENETDOWN => return error.NetworkSubsystemFailed,
5057 ENOMEM => return error.SystemResources,5203 .WSAENOBUFS => return error.SystemResources,
5058 else => |err| return unexpectedErrno(err),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 }
5059 }5219 }
5220 unreachable;
5060 }5221 }
5061}5222}
50625223
...@@ -5071,12 +5232,30 @@ pub const RecvFromError = error{...@@ -5071,12 +5232,30 @@ pub const RecvFromError = error{
50715232
5072 /// Could not allocate kernel memory.5233 /// Could not allocate kernel memory.
5073 SystemResources,5234 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,
5074} || UnexpectedError;5249} || UnexpectedError;
50755250
5251pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {
5252 return recvfrom(sock, buf, flags, null, null);
5253}
5254
5076/// If `sockfd` is opened in non blocking mode, the function will5255/// If `sockfd` is opened in non blocking mode, the function will
5077/// return error.WouldBlock when EAGAIN is received.5256/// return error.WouldBlock when EAGAIN is received.
5078pub fn recvfrom(5257pub fn recvfrom(
5079 sockfd: fd_t,5258 sockfd: socket_t,
5080 buf: []u8,5259 buf: []u8,
5081 flags: u32,5260 flags: u32,
5082 src_addr: ?*sockaddr,5261 src_addr: ?*sockaddr,
...@@ -5084,18 +5263,36 @@ pub fn recvfrom(...@@ -5084,18 +5263,36 @@ pub fn recvfrom(
5084) RecvFromError!usize {5263) RecvFromError!usize {
5085 while (true) {5264 while (true) {
5086 const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);5265 const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);
5087 switch (errno(rc)) {5266 if (builtin.os.tag == .windows) {
5088 0 => return @intCast(usize, rc),5267 if (rc == windows.ws2_32.SOCKET_ERROR) {
5089 EBADF => unreachable, // always a race condition5268 switch (windows.ws2_32.WSAGetLastError()) {
5090 EFAULT => unreachable,5269 .WSANOTINITIALISED => unreachable,
5091 EINVAL => unreachable,5270 .WSAECONNRESET => return error.ConnectionResetByPeer,
5092 ENOTCONN => unreachable,5271 .WSAEINVAL => return error.SocketNotBound,
5093 ENOTSOCK => unreachable,5272 .WSAEMSGSIZE => return error.MessageTooBig,
5094 EINTR => continue,5273 .WSAENETDOWN => return error.NetworkSubsystemFailed,
5095 EAGAIN => return error.WouldBlock,5274 .WSAENOTCONN => return error.SocketNotConnected,
5096 ENOMEM => return error.SystemResources,5275 .WSAEWOULDBLOCK => return error.WouldBlock,
5097 ECONNREFUSED => return error.ConnectionRefused,5276 // TODO: handle more errors
5098 else => |err| return unexpectedErrno(err),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 }
5099 }5296 }
5100 }5297 }
5101}5298}
lib/std/os/bits/windows.zig+14-1
...@@ -172,7 +172,7 @@ pub const AT_REMOVEDIR = 0x200;...@@ -172,7 +172,7 @@ pub const AT_REMOVEDIR = 0x200;
172172
173pub const in_port_t = u16;173pub const in_port_t = u16;
174pub const sa_family_t = ws2_32.ADDRESS_FAMILY;174pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
175pub const socklen_t = u32;175pub const socklen_t = ws2_32.socklen_t;
176176
177pub const sockaddr = ws2_32.sockaddr;177pub const sockaddr = ws2_32.sockaddr;
178pub const sockaddr_in = ws2_32.sockaddr_in;178pub const sockaddr_in = ws2_32.sockaddr_in;
...@@ -243,6 +243,19 @@ pub const IPPROTO_UDP = ws2_32.IPPROTO_UDP;...@@ -243,6 +243,19 @@ pub const IPPROTO_UDP = ws2_32.IPPROTO_UDP;
243pub const IPPROTO_ICMPV6 = ws2_32.IPPROTO_ICMPV6;243pub const IPPROTO_ICMPV6 = ws2_32.IPPROTO_ICMPV6;
244pub const IPPROTO_RM = ws2_32.IPPROTO_RM;244pub 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
246pub const O_RDONLY = 0o0;259pub const O_RDONLY = 0o0;
247pub const O_WRONLY = 0o1;260pub const O_WRONLY = 0o1;
248pub const O_RDWR = 0o2;261pub const O_RDWR = 0o2;
lib/std/os/windows.zig+42
...@@ -1157,6 +1157,14 @@ pub fn WSASocketW(...@@ -1157,6 +1157,14 @@ pub fn WSASocketW(
1157 return rc;1157 return rc;
1158}1158}
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
1160pub fn closesocket(s: ws2_32.SOCKET) !void {1168pub fn closesocket(s: ws2_32.SOCKET) !void {
1161 switch (ws2_32.closesocket(s)) {1169 switch (ws2_32.closesocket(s)) {
1162 0 => {},1170 0 => {},
...@@ -1167,6 +1175,40 @@ pub fn closesocket(s: ws2_32.SOCKET) !void {...@@ -1167,6 +1175,40 @@ pub fn closesocket(s: ws2_32.SOCKET) !void {
1167 }1175 }
1168}1176}
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
1170pub fn WSAIoctl(1212pub fn WSAIoctl(
1171 s: ws2_32.SOCKET,1213 s: ws2_32.SOCKET,
1172 dwIoControlCode: DWORD,1214 dwIoControlCode: DWORD,
lib/std/os/windows/ws2_32.zig+44-4
...@@ -116,7 +116,7 @@ pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred:...@@ -116,7 +116,7 @@ pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred:
116pub const ADDRESS_FAMILY = u16;116pub const ADDRESS_FAMILY = u16;
117117
118// Microsoft use the signed c_int for this, but it should never be negative118// Microsoft use the signed c_int for this, but it should never be negative
119const socklen_t = u32;119pub const socklen_t = u32;
120120
121pub const AF_UNSPEC = 0;121pub const AF_UNSPEC = 0;
122pub const AF_UNIX = 1;122pub const AF_UNIX = 1;
...@@ -234,6 +234,27 @@ pub const WSAMSG = extern struct {...@@ -234,6 +234,27 @@ pub const WSAMSG = extern struct {
234 dwFlags: DWORD,234 dwFlags: DWORD,
235};235};
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
237// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2258// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2
238pub const WinsockError = extern enum(u16) {259pub const WinsockError = extern enum(u16) {
239 /// Specified event object handle is invalid.260 /// Specified event object handle is invalid.
...@@ -734,12 +755,21 @@ pub extern "ws2_32" fn WSAIoctl(...@@ -734,12 +755,21 @@ pub extern "ws2_32" fn WSAIoctl(
734pub extern "ws2_32" fn accept(755pub extern "ws2_32" fn accept(
735 s: SOCKET,756 s: SOCKET,
736 addr: ?*sockaddr,757 addr: ?*sockaddr,
737 addrlen: socklen_t,758 addrlen: ?*c_int,
738) callconv(.Stdcall) SOCKET;759) 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;
739pub extern "ws2_32" fn connect(765pub extern "ws2_32" fn connect(
740 s: SOCKET,766 s: SOCKET,
741 name: *const sockaddr,767 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,
743) callconv(.Stdcall) c_int;773) callconv(.Stdcall) c_int;
744pub extern "ws2_32" fn WSARecv(774pub extern "ws2_32" fn WSARecv(
745 s: SOCKET,775 s: SOCKET,
...@@ -777,10 +807,15 @@ pub extern "ws2_32" fn WSASendTo(...@@ -777,10 +807,15 @@ pub extern "ws2_32" fn WSASendTo(
777 lpNumberOfBytesSent: ?*DWORD,807 lpNumberOfBytesSent: ?*DWORD,
778 dwFlags: DWORD,808 dwFlags: DWORD,
779 lpTo: ?*const sockaddr,809 lpTo: ?*const sockaddr,
780 iTolen: socklen_t,810 iTolen: c_int,
781 lpOverlapped: ?*WSAOVERLAPPED,811 lpOverlapped: ?*WSAOVERLAPPED,
782 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,812 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
783) callconv(.Stdcall) c_int;813) 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;
784pub extern "ws2_32" fn getaddrinfo(819pub extern "ws2_32" fn getaddrinfo(
785 pNodeName: [*:0]const u8,820 pNodeName: [*:0]const u8,
786 pServiceName: [*:0]const u8,821 pServiceName: [*:0]const u8,
...@@ -795,3 +830,8 @@ pub extern "ws2_32" fn ioctlsocket(...@@ -795,3 +830,8 @@ pub extern "ws2_32" fn ioctlsocket(
795 cmd: c_long,830 cmd: c_long,
796 argp: *c_ulong,831 argp: *c_ulong,
797) callconv(.Stdcall) c_int;832) 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;