| ... | ... | @@ -2657,14 +2657,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t |
| 2657 | 2657 | // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations |
| 2658 | 2658 | const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC); |
| 2659 | 2659 | const flags: u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0; |
| 2660 | | const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), @intCast(c_int, protocol), null, 0, flags); |
| 2661 | | if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { |
| 2662 | | .WSAEMFILE => return error.ProcessFdQuotaExceeded, |
| 2663 | | .WSAENOBUFS => return error.SystemResources, |
| 2664 | | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, |
| 2665 | | .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, |
| 2666 | | else => |err| return windows.unexpectedWSAError(err), |
| 2667 | | }; |
| 2660 | const rc = try windows.WSASocketW(@bitCast(i32, domain), @bitCast(i32, filtered_sock_type), @bitCast(i32, protocol), null, 0, flags); |
| 2668 | 2661 | errdefer windows.closesocket(rc) catch unreachable; |
| 2669 | 2662 | if ((socket_type & SOCK_NONBLOCK) != 0) { |
| 2670 | 2663 | var mode: c_ulong = 1; // nonblocking |
| ... | ... | @@ -2741,24 +2734,34 @@ pub const BindError = error{ |
| 2741 | 2734 | } || UnexpectedError; |
| 2742 | 2735 | |
| 2743 | 2736 | /// addr is `*const T` where T is one of the sockaddr |
| 2744 | | pub fn bind(sockfd: fd_t, addr: *const sockaddr, len: socklen_t) BindError!void { |
| 2745 | | const rc = system.bind(sockfd, addr, len); |
| 2746 | | switch (errno(rc)) { |
| 2747 | | 0 => return, |
| 2748 | | EACCES => return error.AccessDenied, |
| 2749 | | EADDRINUSE => return error.AddressInUse, |
| 2750 | | EBADF => unreachable, // always a race condition if this error is returned |
| 2751 | | EINVAL => unreachable, // invalid parameters |
| 2752 | | ENOTSOCK => unreachable, // invalid `sockfd` |
| 2753 | | EADDRNOTAVAIL => return error.AddressNotAvailable, |
| 2754 | | EFAULT => unreachable, // invalid `addr` pointer |
| 2755 | | ELOOP => return error.SymLinkLoop, |
| 2756 | | ENAMETOOLONG => return error.NameTooLong, |
| 2757 | | ENOENT => return error.FileNotFound, |
| 2758 | | ENOMEM => return error.SystemResources, |
| 2759 | | ENOTDIR => return error.NotDir, |
| 2760 | | EROFS => return error.ReadOnlyFileSystem, |
| 2761 | | else => |err| return unexpectedErrno(err), |
| 2737 | pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void { |
| 2738 | const rc = system.bind(sock, addr, len); |
| 2739 | if (builtin.os.tag == .windows) { |
| 2740 | if (rc == windows.ws2_32.SOCKET_ERROR) { |
| 2741 | switch (windows.ws2_32.WSAGetLastError()) { |
| 2742 | // TODO: handle errors |
| 2743 | else => |err| return windows.unexpectedWSAError(err), |
| 2744 | } |
| 2745 | } |
| 2746 | return; |
| 2747 | } else { |
| 2748 | switch (errno(rc)) { |
| 2749 | 0 => return, |
| 2750 | EACCES => return error.AccessDenied, |
| 2751 | EADDRINUSE => return error.AddressInUse, |
| 2752 | EBADF => unreachable, // always a race condition if this error is returned |
| 2753 | EINVAL => unreachable, // invalid parameters |
| 2754 | ENOTSOCK => unreachable, // invalid `sockfd` |
| 2755 | EADDRNOTAVAIL => return error.AddressNotAvailable, |
| 2756 | EFAULT => unreachable, // invalid `addr` pointer |
| 2757 | ELOOP => return error.SymLinkLoop, |
| 2758 | ENAMETOOLONG => return error.NameTooLong, |
| 2759 | ENOENT => return error.FileNotFound, |
| 2760 | ENOMEM => return error.SystemResources, |
| 2761 | ENOTDIR => return error.NotDir, |
| 2762 | EROFS => return error.ReadOnlyFileSystem, |
| 2763 | else => |err| return unexpectedErrno(err), |
| 2764 | } |
| 2762 | 2765 | } |
| 2763 | 2766 | } |
| 2764 | 2767 | |
| ... | ... | @@ -2777,15 +2780,25 @@ const ListenError = error{ |
| 2777 | 2780 | OperationNotSupported, |
| 2778 | 2781 | } || UnexpectedError; |
| 2779 | 2782 | |
| 2780 | | pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { |
| 2781 | | const rc = system.listen(sockfd, backlog); |
| 2782 | | switch (errno(rc)) { |
| 2783 | | 0 => return, |
| 2784 | | EADDRINUSE => return error.AddressInUse, |
| 2785 | | EBADF => unreachable, |
| 2786 | | ENOTSOCK => return error.FileDescriptorNotASocket, |
| 2787 | | EOPNOTSUPP => return error.OperationNotSupported, |
| 2788 | | else => |err| return unexpectedErrno(err), |
| 2783 | pub fn listen(sock: socket_t, backlog: u31) ListenError!void { |
| 2784 | const rc = system.listen(sock, backlog); |
| 2785 | if (builtin.os.tag == .windows) { |
| 2786 | if (rc == windows.ws2_32.SOCKET_ERROR) { |
| 2787 | switch (windows.ws2_32.WSAGetLastError()) { |
| 2788 | // TODO: handle errors |
| 2789 | else => |err| return windows.unexpectedWSAError(err), |
| 2790 | } |
| 2791 | } |
| 2792 | return; |
| 2793 | } else { |
| 2794 | switch (errno(rc)) { |
| 2795 | 0 => return, |
| 2796 | EADDRINUSE => return error.AddressInUse, |
| 2797 | EBADF => unreachable, |
| 2798 | ENOTSOCK => return error.FileDescriptorNotASocket, |
| 2799 | EOPNOTSUPP => return error.OperationNotSupported, |
| 2800 | else => |err| return unexpectedErrno(err), |
| 2801 | } |
| 2789 | 2802 | } |
| 2790 | 2803 | } |
| 2791 | 2804 | |
| ... | ... | @@ -2822,19 +2835,19 @@ pub const AcceptError = error{ |
| 2822 | 2835 | pub fn accept( |
| 2823 | 2836 | /// This argument is a socket that has been created with `socket`, bound to a local address |
| 2824 | 2837 | /// with `bind`, and is listening for connections after a `listen`. |
| 2825 | | sockfd: fd_t, |
| 2838 | sock: socket_t, |
| 2826 | 2839 | /// This argument is a pointer to a sockaddr structure. This structure is filled in with the |
| 2827 | 2840 | /// address of the peer socket, as known to the communications layer. The exact format of the |
| 2828 | 2841 | /// address returned addr is determined by the socket's address family (see `socket` and the |
| 2829 | 2842 | /// respective protocol man pages). |
| 2830 | | addr: *sockaddr, |
| 2843 | addr: ?*sockaddr, |
| 2831 | 2844 | /// This argument is a value-result argument: the caller must initialize it to contain the |
| 2832 | 2845 | /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size |
| 2833 | 2846 | /// of the peer address. |
| 2834 | 2847 | /// |
| 2835 | 2848 | /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` |
| 2836 | 2849 | /// will return a value greater than was supplied to the call. |
| 2837 | | addr_size: *socklen_t, |
| 2850 | addr_size: ?*socklen_t, |
| 2838 | 2851 | /// The following values can be bitwise ORed in flags to obtain different behavior: |
| 2839 | 2852 | /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`) |
| 2840 | 2853 | /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve |
| ... | ... | @@ -2842,46 +2855,58 @@ pub fn accept( |
| 2842 | 2855 | /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the |
| 2843 | 2856 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. |
| 2844 | 2857 | flags: u32, |
| 2845 | | ) AcceptError!fd_t { |
| 2846 | | const have_accept4 = comptime !std.Target.current.isDarwin(); |
| 2858 | ) AcceptError!socket_t { |
| 2859 | const have_accept4 = comptime !(std.Target.current.isDarwin() or builtin.os.tag == .windows); |
| 2847 | 2860 | assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s) |
| 2848 | 2861 | |
| 2849 | | while (true) { |
| 2862 | const accepted_sock = while (true) { |
| 2850 | 2863 | const rc = if (have_accept4) |
| 2851 | | system.accept4(sockfd, addr, addr_size, flags) |
| 2864 | system.accept4(sock, addr, addr_size, flags) |
| 2852 | 2865 | else |
| 2853 | | system.accept(sockfd, addr, addr_size); |
| 2866 | system.accept(sock, addr, addr_size); |
| 2854 | 2867 | |
| 2855 | | switch (errno(rc)) { |
| 2856 | | 0 => { |
| 2857 | | const fd = @intCast(fd_t, rc); |
| 2858 | | if (!have_accept4) { |
| 2859 | | try setSockFlags(fd, flags); |
| 2868 | if (builtin.os.tag == .windows) { |
| 2869 | if (rc == windows.ws2_32.INVALID_SOCKET) { |
| 2870 | switch (windows.ws2_32.WSAGetLastError()) { |
| 2871 | // TODO: handle errors |
| 2872 | else => |err| return windows.unexpectedWSAError(err), |
| 2860 | 2873 | } |
| 2861 | | return fd; |
| 2862 | | }, |
| 2863 | | EINTR => continue, |
| 2864 | | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 2865 | | loop.waitUntilFdReadable(sockfd); |
| 2866 | | continue; |
| 2867 | 2874 | } else { |
| 2868 | | return error.WouldBlock; |
| 2869 | | }, |
| 2870 | | EBADF => unreachable, // always a race condition |
| 2871 | | ECONNABORTED => return error.ConnectionAborted, |
| 2872 | | EFAULT => unreachable, |
| 2873 | | EINVAL => unreachable, |
| 2874 | | ENOTSOCK => unreachable, |
| 2875 | | EMFILE => return error.ProcessFdQuotaExceeded, |
| 2876 | | ENFILE => return error.SystemFdQuotaExceeded, |
| 2877 | | ENOBUFS => return error.SystemResources, |
| 2878 | | ENOMEM => return error.SystemResources, |
| 2879 | | EOPNOTSUPP => unreachable, |
| 2880 | | EPROTO => return error.ProtocolFailure, |
| 2881 | | EPERM => return error.BlockedByFirewall, |
| 2882 | | else => |err| return unexpectedErrno(err), |
| 2875 | break rc; |
| 2876 | } |
| 2877 | } else { |
| 2878 | switch (errno(rc)) { |
| 2879 | 0 => { |
| 2880 | break @intCast(socket_t, rc); |
| 2881 | }, |
| 2882 | EINTR => continue, |
| 2883 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 2884 | loop.waitUntilFdReadable(sock); |
| 2885 | continue; |
| 2886 | } else { |
| 2887 | return error.WouldBlock; |
| 2888 | }, |
| 2889 | EBADF => unreachable, // always a race condition |
| 2890 | ECONNABORTED => return error.ConnectionAborted, |
| 2891 | EFAULT => unreachable, |
| 2892 | EINVAL => unreachable, |
| 2893 | ENOTSOCK => unreachable, |
| 2894 | EMFILE => return error.ProcessFdQuotaExceeded, |
| 2895 | ENFILE => return error.SystemFdQuotaExceeded, |
| 2896 | ENOBUFS => return error.SystemResources, |
| 2897 | ENOMEM => return error.SystemResources, |
| 2898 | EOPNOTSUPP => unreachable, |
| 2899 | EPROTO => return error.ProtocolFailure, |
| 2900 | EPERM => return error.BlockedByFirewall, |
| 2901 | else => |err| return unexpectedErrno(err), |
| 2902 | } |
| 2883 | 2903 | } |
| 2904 | } else unreachable; |
| 2905 | |
| 2906 | if (!have_accept4) { |
| 2907 | try setSockFlags(accepted_sock, flags); |
| 2884 | 2908 | } |
| 2909 | return accepted_sock; |
| 2885 | 2910 | } |
| 2886 | 2911 | |
| 2887 | 2912 | pub const EpollCreateError = error{ |
| ... | ... | @@ -2997,16 +3022,27 @@ pub const GetSockNameError = error{ |
| 2997 | 3022 | SystemResources, |
| 2998 | 3023 | } || UnexpectedError; |
| 2999 | 3024 | |
| 3000 | | pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { |
| 3001 | | switch (errno(system.getsockname(sockfd, addr, addrlen))) { |
| 3002 | | 0 => return, |
| 3003 | | else => |err| return unexpectedErrno(err), |
| 3025 | pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { |
| 3026 | const rc = system.getsockname(sock, addr, addrlen); |
| 3027 | if (builtin.os.tag == .windows) { |
| 3028 | if (rc == windows.ws2_32.SOCKET_ERROR) { |
| 3029 | switch (windows.ws2_32.WSAGetLastError()) { |
| 3030 | // TODO: handle errors |
| 3031 | else => |err| return windows.unexpectedWSAError(err), |
| 3032 | } |
| 3033 | } |
| 3034 | return; |
| 3035 | } else { |
| 3036 | switch (errno(rc)) { |
| 3037 | 0 => return, |
| 3038 | else => |err| return unexpectedErrno(err), |
| 3004 | 3039 | |
| 3005 | | EBADF => unreachable, // always a race condition |
| 3006 | | EFAULT => unreachable, |
| 3007 | | EINVAL => unreachable, // invalid parameters |
| 3008 | | ENOTSOCK => unreachable, |
| 3009 | | ENOBUFS => return error.SystemResources, |
| 3040 | EBADF => unreachable, // always a race condition |
| 3041 | EFAULT => unreachable, |
| 3042 | EINVAL => unreachable, // invalid parameters |
| 3043 | ENOTSOCK => unreachable, |
| 3044 | ENOBUFS => return error.SystemResources, |
| 3045 | } |
| 3010 | 3046 | } |
| 3011 | 3047 | } |
| 3012 | 3048 | |
| ... | ... | @@ -3052,9 +3088,9 @@ pub const ConnectError = error{ |
| 3052 | 3088 | } || UnexpectedError; |
| 3053 | 3089 | |
| 3054 | 3090 | /// Initiate a connection on a socket. |
| 3055 | | pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { |
| 3091 | pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { |
| 3056 | 3092 | if (builtin.os.tag == .windows) { |
| 3057 | | const rc = windows.ws2_32.connect(sockfd, sock_addr, len); |
| 3093 | const rc = windows.ws2_32.connect(sock, sock_addr, len); |
| 3058 | 3094 | if (rc == 0) return; |
| 3059 | 3095 | switch (windows.ws2_32.WSAGetLastError()) { |
| 3060 | 3096 | .WSAEADDRINUSE => return error.AddressInUse, |
| ... | ... | @@ -3077,7 +3113,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con |
| 3077 | 3113 | } |
| 3078 | 3114 | |
| 3079 | 3115 | while (true) { |
| 3080 | | switch (errno(system.connect(sockfd, sock_addr, len))) { |
| 3116 | switch (errno(system.connect(sock, sock_addr, len))) { |
| 3081 | 3117 | 0 => return, |
| 3082 | 3118 | EACCES => return error.PermissionDenied, |
| 3083 | 3119 | EPERM => return error.PermissionDenied, |
| ... | ... | @@ -3086,8 +3122,8 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con |
| 3086 | 3122 | EAFNOSUPPORT => return error.AddressFamilyNotSupported, |
| 3087 | 3123 | EAGAIN, EINPROGRESS => { |
| 3088 | 3124 | const loop = std.event.Loop.instance orelse return error.WouldBlock; |
| 3089 | | loop.waitUntilFdWritable(sockfd); |
| 3090 | | return getsockoptError(sockfd); |
| 3125 | loop.waitUntilFdWritable(sock); |
| 3126 | return getsockoptError(sock); |
| 3091 | 3127 | }, |
| 3092 | 3128 | EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed. |
| 3093 | 3129 | EBADF => unreachable, // sockfd is not a valid open file descriptor. |
| ... | ... | @@ -3928,32 +3964,46 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { |
| 3928 | 3964 | } |
| 3929 | 3965 | } |
| 3930 | 3966 | |
| 3931 | | fn setSockFlags(fd: fd_t, flags: u32) !void { |
| 3967 | fn setSockFlags(sock: socket_t, flags: u32) !void { |
| 3932 | 3968 | if ((flags & SOCK_CLOEXEC) != 0) { |
| 3933 | | var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) { |
| 3934 | | error.FileBusy => unreachable, |
| 3935 | | error.Locked => unreachable, |
| 3936 | | else => |e| return e, |
| 3937 | | }; |
| 3938 | | fd_flags |= FD_CLOEXEC; |
| 3939 | | _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) { |
| 3940 | | error.FileBusy => unreachable, |
| 3941 | | error.Locked => unreachable, |
| 3942 | | else => |e| return e, |
| 3943 | | }; |
| 3969 | if (builtin.os.tag == .windows) { |
| 3970 | // TODO: Find out if this is supported for sockets |
| 3971 | } else { |
| 3972 | var fd_flags = fcntl(sock, F_GETFD, 0) catch |err| switch (err) { |
| 3973 | error.FileBusy => unreachable, |
| 3974 | error.Locked => unreachable, |
| 3975 | else => |e| return e, |
| 3976 | }; |
| 3977 | fd_flags |= FD_CLOEXEC; |
| 3978 | _ = fcntl(sock, F_SETFD, fd_flags) catch |err| switch (err) { |
| 3979 | error.FileBusy => unreachable, |
| 3980 | error.Locked => unreachable, |
| 3981 | else => |e| return e, |
| 3982 | }; |
| 3983 | } |
| 3944 | 3984 | } |
| 3945 | 3985 | if ((flags & SOCK_NONBLOCK) != 0) { |
| 3946 | | var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) { |
| 3947 | | error.FileBusy => unreachable, |
| 3948 | | error.Locked => unreachable, |
| 3949 | | else => |e| return e, |
| 3950 | | }; |
| 3951 | | fl_flags |= O_NONBLOCK; |
| 3952 | | _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) { |
| 3953 | | error.FileBusy => unreachable, |
| 3954 | | error.Locked => unreachable, |
| 3955 | | else => |e| return e, |
| 3956 | | }; |
| 3986 | if (builtin.os.tag == .windows) { |
| 3987 | var mode: c_ulong = 1; |
| 3988 | if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) { |
| 3989 | switch (windows.ws2_32.WSAGetLastError()) { |
| 3990 | // TODO: handle errors |
| 3991 | else => |err| return windows.unexpectedWSAError(err), |
| 3992 | } |
| 3993 | } |
| 3994 | } else { |
| 3995 | var fl_flags = fcntl(sock, F_GETFL, 0) catch |err| switch (err) { |
| 3996 | error.FileBusy => unreachable, |
| 3997 | error.Locked => unreachable, |
| 3998 | else => |e| return e, |
| 3999 | }; |
| 4000 | fl_flags |= O_NONBLOCK; |
| 4001 | _ = fcntl(sock, F_SETFL, fl_flags) catch |err| switch (err) { |
| 4002 | error.FileBusy => unreachable, |
| 4003 | error.Locked => unreachable, |
| 4004 | else => |e| return e, |
| 4005 | }; |
| 4006 | } |
| 3957 | 4007 | } |
| 3958 | 4008 | } |
| 3959 | 4009 | |