| ... | @@ -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 operations | 2646 | // 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; // nonblocking | 2652 | var mode: c_ulong = 1; // nonblocking |
| ... | @@ -2727,28 +2720,55 @@ pub const BindError = error{ | ... | @@ -2727,28 +2720,55 @@ pub const BindError = error{ |
| 2727 | | 2720 | |
| 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; |
| 2731 | | 2731 | |
| 2732 | /// addr is `*const T` where T is one of the sockaddr | 2732 | /// addr is `*const T` where T is one of the sockaddr |
| 2733 | pub fn bind(sockfd: fd_t, addr: *const sockaddr, len: socklen_t) BindError!void { | 2733 | pub 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 returned | 2739 | .WSAEACCES => return error.AccessDenied, |
| 2740 | EINVAL => unreachable, // invalid parameters | 2740 | .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` pointer | 2743 | .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 | } |
| 2753 | | 2773 | |
| 2754 | const ListenError = error{ | 2774 | const ListenError = error{ |
| ... | @@ -2764,23 +2784,57 @@ const ListenError = error{ | ... | @@ -2764,23 +2784,57 @@ const ListenError = error{ |
| 2764 | | 2784 | |
| 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; |
| 2768 | | 2801 | |
| 2769 | pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { | 2802 | pub 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 | } |
| 2780 | | 2831 | |
| 2781 | pub const AcceptError = error{ | 2832 | pub const AcceptError = error{ |
| 2782 | ConnectionAborted, | 2833 | ConnectionAborted, |
| 2783 | | 2834 | |
| | 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, |
| 2786 | | 2840 | |
| ... | @@ -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/or | 2860 | /// 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; |
| 2810 | | 2874 | |
| 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{ |
| 2814 | pub fn accept( | 2878 | pub fn accept( |
| 2815 | /// This argument is a socket that has been created with `socket`, bound to a local address | 2879 | /// 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 the | 2882 | /// 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 the | 2883 | /// 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 the | 2884 | /// 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 the | 2887 | /// 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 size | 2888 | /// 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 achieve | 2896 | /// 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 the | 2898 | /// * `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) |
| 2840 | | 2904 | |
| 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 | else | 2908 | else |
| 2845 | system.accept(sockfd, addr, addr_size); | 2909 | system.accept(sock, addr, addr_size); |
| 2846 | | 2910 | |
| 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 condition | 2929 | 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 | } |
| 2873 | | 2957 | |
| 2874 | pub const EpollCreateError = error{ | 2958 | pub 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 { |
| 2982 | pub const GetSockNameError = error{ | 3066 | pub 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; |
| 2986 | | 3078 | |
| 2987 | pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { | 3079 | pub 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), |
| 2991 | | 3097 | |
| 2992 | EBADF => unreachable, // always a race condition | 3098 | EBADF => unreachable, // always a race condition |
| 2993 | EFAULT => unreachable, | 3099 | EFAULT => unreachable, |
| 2994 | EINVAL => unreachable, // invalid parameters | 3100 | 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 | } |
| 2999 | | 3106 | |
| ... | @@ -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 will | 3149 | /// 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. |
| 3044 | pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { | 3151 | pub 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 | } |
| 3067 | | 3174 | |
| 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 | } |
| 3923 | | 4030 | |
| 3924 | fn setSockFlags(fd: fd_t, flags: u32) !void { | 4031 | fn 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 | } |
| 3952 | | 4076 | |
| ... | @@ -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, the | 4668 | /// 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; |
| 4548 | | 4674 | |
| 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. |
| 4574 | pub fn sendto( | 4700 | pub 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 condition | 4716 | .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 specified | 4722 | } 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. |
| 4628 | pub fn send( | 4771 | pub 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 | } |
| 5043 | | 5186 | |
| 5044 | pub const PollError = error{ | 5187 | pub 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{ |
| 5049 | pub fn poll(fds: []pollfd, timeout: i32) PollError!usize { | 5195 | pub 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 | } |
| 5062 | | 5223 | |
| ... | @@ -5071,12 +5232,30 @@ pub const RecvFromError = error{ | ... | @@ -5071,12 +5232,30 @@ pub const RecvFromError = error{ |
| 5071 | | 5232 | |
| 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; |
| 5075 | | 5250 | |
| | 5251 | pub 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 will | 5255 | /// 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. |
| 5078 | pub fn recvfrom( | 5257 | pub 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 condition | 5268 | 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 | } |