authorgravatar for BarabasGitHub@users.noreply.github.comBas van den Berg <BarabasGitHub@users.noreply.github.com> 2020-09-02 23:53:29+02:00
committergravatar for BarabasGitHub@users.noreply.github.comBas van den Berg <BarabasGitHub@users.noreply.github.com> 2020-09-02 23:53:29+02:00
logd80554cedf313bc78f0419faf84776bd987263df
treebefd1953ca09d583118b4b845e582f743f587f1d
parent12ce6eb8f65e6de5920c713cf2767e4b8ba0f1d3

Made some changes and additions to the networking to make it work on windows.


4 files changed, 201 insertions(+), 110 deletions(-)

lib/std/os.zig+156-106
......@@ -2657,14 +2657,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
26572657 // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations
26582658 const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC);
26592659 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);
26682661 errdefer windows.closesocket(rc) catch unreachable;
26692662 if ((socket_type & SOCK_NONBLOCK) != 0) {
26702663 var mode: c_ulong = 1; // nonblocking
......@@ -2741,24 +2734,34 @@ pub const BindError = error{
27412734} || UnexpectedError;
27422735
27432736/// addr is `*const T` where T is one of the sockaddr
2744pub 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),
2737pub 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 }
27622765 }
27632766}
27642767
......@@ -2777,15 +2780,25 @@ const ListenError = error{
27772780 OperationNotSupported,
27782781} || UnexpectedError;
27792782
2780pub 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),
2783pub 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 }
27892802 }
27902803}
27912804
......@@ -2822,19 +2835,19 @@ pub const AcceptError = error{
28222835pub fn accept(
28232836 /// This argument is a socket that has been created with `socket`, bound to a local address
28242837 /// with `bind`, and is listening for connections after a `listen`.
2825 sockfd: fd_t,
2838 sock: socket_t,
28262839 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the
28272840 /// address of the peer socket, as known to the communications layer. The exact format of the
28282841 /// address returned addr is determined by the socket's address family (see `socket` and the
28292842 /// respective protocol man pages).
2830 addr: *sockaddr,
2843 addr: ?*sockaddr,
28312844 /// This argument is a value-result argument: the caller must initialize it to contain the
28322845 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
28332846 /// of the peer address.
28342847 ///
28352848 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
28362849 /// will return a value greater than was supplied to the call.
2837 addr_size: *socklen_t,
2850 addr_size: ?*socklen_t,
28382851 /// The following values can be bitwise ORed in flags to obtain different behavior:
28392852 /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`)
28402853 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
......@@ -2842,46 +2855,58 @@ pub fn accept(
28422855 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
28432856 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
28442857 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);
28472860 assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s)
28482861
2849 while (true) {
2862 const accepted_sock = while (true) {
28502863 const rc = if (have_accept4)
2851 system.accept4(sockfd, addr, addr_size, flags)
2864 system.accept4(sock, addr, addr_size, flags)
28522865 else
2853 system.accept(sockfd, addr, addr_size);
2866 system.accept(sock, addr, addr_size);
28542867
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),
28602873 }
2861 return fd;
2862 },
2863 EINTR => continue,
2864 EAGAIN => if (std.event.Loop.instance) |loop| {
2865 loop.waitUntilFdReadable(sockfd);
2866 continue;
28672874 } 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 }
28832903 }
2904 } else unreachable;
2905
2906 if (!have_accept4) {
2907 try setSockFlags(accepted_sock, flags);
28842908 }
2909 return accepted_sock;
28852910}
28862911
28872912pub const EpollCreateError = error{
......@@ -2997,16 +3022,27 @@ pub const GetSockNameError = error{
29973022 SystemResources,
29983023} || UnexpectedError;
29993024
3000pub 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),
3025pub 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),
30043039
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 }
30103046 }
30113047}
30123048
......@@ -3052,9 +3088,9 @@ pub const ConnectError = error{
30523088} || UnexpectedError;
30533089
30543090/// Initiate a connection on a socket.
3055pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
3091pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
30563092 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);
30583094 if (rc == 0) return;
30593095 switch (windows.ws2_32.WSAGetLastError()) {
30603096 .WSAEADDRINUSE => return error.AddressInUse,
......@@ -3077,7 +3113,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
30773113 }
30783114
30793115 while (true) {
3080 switch (errno(system.connect(sockfd, sock_addr, len))) {
3116 switch (errno(system.connect(sock, sock_addr, len))) {
30813117 0 => return,
30823118 EACCES => return error.PermissionDenied,
30833119 EPERM => return error.PermissionDenied,
......@@ -3086,8 +3122,8 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
30863122 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
30873123 EAGAIN, EINPROGRESS => {
30883124 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);
30913127 },
30923128 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
30933129 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 {
39283964 }
39293965}
39303966
3931fn setSockFlags(fd: fd_t, flags: u32) !void {
3967fn setSockFlags(sock: socket_t, flags: u32) !void {
39323968 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 }
39443984 }
39453985 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 }
39574007 }
39584008}
39594009
lib/std/os/bits/windows.zig+1-1
......@@ -172,7 +172,7 @@ pub const AT_REMOVEDIR = 0x200;
172172
173173pub const in_port_t = u16;
174174pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
175pub const socklen_t = u32;
175pub const socklen_t = ws2_32.socklen_t;
176176
177177pub const sockaddr = ws2_32.sockaddr;
178178pub const sockaddr_in = ws2_32.sockaddr_in;
lib/std/os/windows.zig+27
......@@ -1153,6 +1153,14 @@ pub fn WSASocketW(
11531153 return rc;
11541154}
11551155
1156pub fn bind(s: ws2_32.SOCKET, name: *const ws2_32.sockaddr, namelen: ws2_32.socklen_t) i32 {
1157 return ws2_32.bind(s, name, namelen);
1158}
1159
1160pub fn listen(s: ws2_32.SOCKET, backlog: u31) i32 {
1161 return ws2_32.listen(s, backlog);
1162}
1163
11561164pub fn closesocket(s: ws2_32.SOCKET) !void {
11571165 switch (ws2_32.closesocket(s)) {
11581166 0 => {},
......@@ -1163,6 +1171,25 @@ pub fn closesocket(s: ws2_32.SOCKET) !void {
11631171 }
11641172}
11651173
1174pub fn accept(s: ws2_32.SOCKET, name: ?*ws2_32.sockaddr, namelen: ?*ws2_32.socklen_t) ws2_32.SOCKET {
1175 assert((name == null) == (namelen == null));
1176 if (namelen) |name_length| {
1177 var os_namelen: c_int = name_length.*;
1178 const sock = ws2_32.accept(s, name, &os_namelen);
1179 name_length.* = @intCast(ws2_32.socklen_t, os_namelen);
1180 return sock;
1181 } else {
1182 return ws2_32.accept(s, null, null);
1183 }
1184}
1185
1186pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
1187 var os_namelen: c_int = namelen.*;
1188 const rc = ws2_32.getsockname(s, name, &os_namelen);
1189 namelen.* = @intCast(ws2_32.socklen_t, os_namelen);
1190 return rc;
1191}
1192
11661193pub fn WSAIoctl(
11671194 s: ws2_32.SOCKET,
11681195 dwIoControlCode: DWORD,
lib/std/os/windows/ws2_32.zig+17-3
......@@ -116,7 +116,7 @@ pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred:
116116pub const ADDRESS_FAMILY = u16;
117117
118118// Microsoft use the signed c_int for this, but it should never be negative
119const socklen_t = u32;
119pub const socklen_t = u31;
120120
121121pub const AF_UNSPEC = 0;
122122pub const AF_UNIX = 1;
......@@ -734,12 +734,21 @@ pub extern "ws2_32" fn WSAIoctl(
734734pub extern "ws2_32" fn accept(
735735 s: SOCKET,
736736 addr: ?*sockaddr,
737 addrlen: socklen_t,
737 addrlen: ?*c_int,
738738) callconv(.Stdcall) SOCKET;
739pub extern "ws2_32" fn bind(
740 s: SOCKET,
741 addr: ?*const sockaddr,
742 addrlen: c_int,
743) callconv(.Stdcall) c_int;
739744pub extern "ws2_32" fn connect(
740745 s: SOCKET,
741746 name: *const sockaddr,
742 namelen: socklen_t,
747 namelen: c_int,
748) callconv(.Stdcall) c_int;
749pub extern "ws2_32" fn listen(
750 s: SOCKET,
751 backlog: c_int,
743752) callconv(.Stdcall) c_int;
744753pub extern "ws2_32" fn WSARecv(
745754 s: SOCKET,
......@@ -795,3 +804,8 @@ pub extern "ws2_32" fn ioctlsocket(
795804 cmd: c_long,
796805 argp: *c_ulong,
797806) callconv(.Stdcall) c_int;
807pub extern "ws2_32" fn getsockname(
808 s: SOCKET,
809 name: *sockaddr,
810 namelen: *c_int,
811) callconv(.Stdcall) c_int;