diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-10-22 16:59:15 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-10-22 16:59:15 -0700 |
| commit | 569f7ce49ea778864636316cfe41acb3944cf3d4 (patch) | |
| tree | a54f7eb5f3e57b5d774bb05d7f5c663efb2f52b8 /lib/std/os.zig | |
| parent | ddd39b994b1eb9751d06227c6db02f15a5f71e9f (diff) | |
| parent | 127fa8009011e19d552ffdd834c6a607498f1c1e (diff) | |
| download | zig-569f7ce49ea778864636316cfe41acb3944cf3d4.tar.gz zig-569f7ce49ea778864636316cfe41acb3944cf3d4.zip | |
Merge branch 'improve-windows-networking'
of https://github.com/BarabasGitHub/zig into
BarabasGitHub-improve-windows-networking
Conflicts:
lib/std/os.zig
This commit resolves conflicts with the changes to std.os which removed
the EAGAIN error handling interactions with the event loop. The solution
to the conflict was to apply EAGAIN => return error.WouldBlock into the
improved windows networking branch.
Diffstat (limited to 'lib/std/os.zig')
| -rw-r--r-- | lib/std/os.zig | 481 |
1 files changed, 339 insertions, 142 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig index 4ccdf57ad3..be1fe3e5f4 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2646,14 +2646,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC); const flags: u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0; - const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), @intCast(c_int, protocol), null, 0, flags); - if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { - .WSAEMFILE => return error.ProcessFdQuotaExceeded, - .WSAENOBUFS => return error.SystemResources, - .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, - .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, - else => |err| return windows.unexpectedWSAError(err), - }; + const rc = try windows.WSASocketW(@bitCast(i32, domain), @bitCast(i32, filtered_sock_type), @bitCast(i32, protocol), null, 0, flags); errdefer windows.closesocket(rc) catch unreachable; if ((socket_type & SOCK_NONBLOCK) != 0) { var mode: c_ulong = 1; // nonblocking @@ -2727,28 +2720,55 @@ pub const BindError = error{ /// The socket inode would reside on a read-only filesystem. ReadOnlyFileSystem, + + /// The network subsystem has failed. + NetworkSubsystemFailed, + + FileDescriptorNotASocket, + + AlreadyBound, } || UnexpectedError; /// addr is `*const T` where T is one of the sockaddr -pub fn bind(sockfd: fd_t, addr: *const sockaddr, len: socklen_t) BindError!void { - const rc = system.bind(sockfd, addr, len); - switch (errno(rc)) { - 0 => return, - EACCES => return error.AccessDenied, - EADDRINUSE => return error.AddressInUse, - EBADF => unreachable, // always a race condition if this error is returned - EINVAL => unreachable, // invalid parameters - ENOTSOCK => unreachable, // invalid `sockfd` - EADDRNOTAVAIL => return error.AddressNotAvailable, - EFAULT => unreachable, // invalid `addr` pointer - ELOOP => return error.SymLinkLoop, - ENAMETOOLONG => return error.NameTooLong, - ENOENT => return error.FileNotFound, - ENOMEM => return error.SystemResources, - ENOTDIR => return error.NotDir, - EROFS => return error.ReadOnlyFileSystem, - else => |err| return unexpectedErrno(err), +pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void { + const rc = system.bind(sock, addr, len); + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, // not initialized WSA + .WSAEACCES => return error.AccessDenied, + .WSAEADDRINUSE => return error.AddressInUse, + .WSAEADDRNOTAVAIL => return error.AddressNotAvailable, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEFAULT => unreachable, // invalid pointers + .WSAEINVAL => return error.AlreadyBound, + .WSAENOBUFS => return error.SystemResources, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + else => |err| return windows.unexpectedWSAError(err), + } + unreachable; + } + return; + } else { + switch (errno(rc)) { + 0 => return, + EACCES => return error.AccessDenied, + EADDRINUSE => return error.AddressInUse, + EBADF => unreachable, // always a race condition if this error is returned + EINVAL => unreachable, // invalid parameters + ENOTSOCK => unreachable, // invalid `sockfd` + EADDRNOTAVAIL => return error.AddressNotAvailable, + EFAULT => unreachable, // invalid `addr` pointer + ELOOP => return error.SymLinkLoop, + ENAMETOOLONG => return error.NameTooLong, + ENOENT => return error.FileNotFound, + ENOMEM => return error.SystemResources, + ENOTDIR => return error.NotDir, + EROFS => return error.ReadOnlyFileSystem, + else => |err| return unexpectedErrno(err), + } } + unreachable; } const ListenError = error{ @@ -2764,23 +2784,57 @@ const ListenError = error{ /// The socket is not of a type that supports the listen() operation. OperationNotSupported, + + /// The network subsystem has failed. + NetworkSubsystemFailed, + + /// Ran out of system resources + /// On Windows it can either run out of socket descriptors or buffer space + SystemResources, + + /// Already connected + AlreadyConnected, + + /// Socket has not been bound yet + SocketNotBound, } || UnexpectedError; -pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { - const rc = system.listen(sockfd, backlog); - switch (errno(rc)) { - 0 => return, - EADDRINUSE => return error.AddressInUse, - EBADF => unreachable, - ENOTSOCK => return error.FileDescriptorNotASocket, - EOPNOTSUPP => return error.OperationNotSupported, - else => |err| return unexpectedErrno(err), +pub fn listen(sock: socket_t, backlog: u31) ListenError!void { + const rc = system.listen(sock, backlog); + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, // not initialized WSA + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAEADDRINUSE => return error.AddressInUse, + .WSAEISCONN => return error.AlreadyConnected, + .WSAEINVAL => return error.SocketNotBound, + .WSAEMFILE, .WSAENOBUFS => return error.SystemResources, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => return error.OperationNotSupported, + .WSAEINPROGRESS => unreachable, + else => |err| return windows.unexpectedWSAError(err), + } + } + return; + } else { + switch (errno(rc)) { + 0 => return, + EADDRINUSE => return error.AddressInUse, + EBADF => unreachable, + ENOTSOCK => return error.FileDescriptorNotASocket, + EOPNOTSUPP => return error.OperationNotSupported, + else => |err| return unexpectedErrno(err), + } } } pub const AcceptError = error{ ConnectionAborted, + /// The file descriptor sockfd does not refer to a socket. + FileDescriptorNotASocket, + /// The per-process limit on the number of open file descriptors has been reached. ProcessFdQuotaExceeded, @@ -2806,6 +2860,16 @@ pub const AcceptError = error{ /// Permission to create a socket of the specified type and/or /// protocol is denied. PermissionDenied, + + /// An incoming connection was indicated, but was subsequently terminated by the + /// remote peer prior to accepting the call. + ConnectionResetByPeer, + + /// The network subsystem has failed. + NetworkSubsystemFailed, + + /// The referenced socket is not a type that supports connection-oriented service. + OperationNotSupported, } || UnexpectedError; /// Accept a connection on a socket. @@ -2814,19 +2878,19 @@ pub const AcceptError = error{ pub fn accept( /// This argument is a socket that has been created with `socket`, bound to a local address /// with `bind`, and is listening for connections after a `listen`. - sockfd: fd_t, + sock: socket_t, /// This argument is a pointer to a sockaddr structure. This structure is filled in with the /// address of the peer socket, as known to the communications layer. The exact format of the /// address returned addr is determined by the socket's address family (see `socket` and the /// respective protocol man pages). - addr: *sockaddr, + addr: ?*sockaddr, /// This argument is a value-result argument: the caller must initialize it to contain the /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size /// of the peer address. /// /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` /// will return a value greater than was supplied to the call. - addr_size: *socklen_t, + addr_size: ?*socklen_t, /// The following values can be bitwise ORed in flags to obtain different behavior: /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`) /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve @@ -2834,41 +2898,61 @@ pub fn accept( /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. flags: u32, -) AcceptError!fd_t { - const have_accept4 = comptime !std.Target.current.isDarwin(); +) AcceptError!socket_t { + const have_accept4 = comptime !(std.Target.current.isDarwin() or builtin.os.tag == .windows); assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s) - while (true) { + const accepted_sock = while (true) { const rc = if (have_accept4) - system.accept4(sockfd, addr, addr_size, flags) + system.accept4(sock, addr, addr_size, flags) else - system.accept(sockfd, addr, addr_size); + system.accept(sock, addr, addr_size); - switch (errno(rc)) { - 0 => { - const fd = @intCast(fd_t, rc); - if (!have_accept4) { - try setSockFlags(fd, flags); + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.INVALID_SOCKET) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, // not initialized WSA + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAEFAULT => unreachable, + .WSAEINVAL => return error.SocketNotListening, + .WSAEMFILE => return error.ProcessFdQuotaExceeded, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENOBUFS => return error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => return error.OperationNotSupported, + .WSAEWOULDBLOCK => return error.WouldBlock, + else => |err| return windows.unexpectedWSAError(err), } - return fd; - }, - EINTR => continue, - EAGAIN => return error.WouldBlock, - EBADF => unreachable, // always a race condition - ECONNABORTED => return error.ConnectionAborted, - EFAULT => unreachable, - EINVAL => return error.SocketNotListening, - ENOTSOCK => unreachable, - EMFILE => return error.ProcessFdQuotaExceeded, - ENFILE => return error.SystemFdQuotaExceeded, - ENOBUFS => return error.SystemResources, - ENOMEM => return error.SystemResources, - EOPNOTSUPP => unreachable, - EPROTO => return error.ProtocolFailure, - EPERM => return error.BlockedByFirewall, - else => |err| return unexpectedErrno(err), + } else { + break rc; + } + } else { + switch (errno(rc)) { + 0 => { + break @intCast(socket_t, rc); + }, + EINTR => continue, + EAGAIN => return error.WouldBlock, + EBADF => unreachable, // always a race condition + ECONNABORTED => return error.ConnectionAborted, + EFAULT => unreachable, + EINVAL => return error.SocketNotListening, + ENOTSOCK => unreachable, + EMFILE => return error.ProcessFdQuotaExceeded, + ENFILE => return error.SystemFdQuotaExceeded, + ENOBUFS => return error.SystemResources, + ENOMEM => return error.SystemResources, + EOPNOTSUPP => unreachable, + EPROTO => return error.ProtocolFailure, + EPERM => return error.BlockedByFirewall, + else => |err| return unexpectedErrno(err), + } } + } else unreachable; + + if (!have_accept4) { + try setSockFlags(accepted_sock, flags); } + return accepted_sock; } pub const EpollCreateError = error{ @@ -2982,18 +3066,41 @@ pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 { pub const GetSockNameError = error{ /// Insufficient resources were available in the system to perform the operation. SystemResources, + + /// The network subsystem has failed. + NetworkSubsystemFailed, + + /// Socket hasn't been bound yet + SocketNotBound, + + FileDescriptorNotASocket, } || UnexpectedError; -pub fn getsockname(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { - switch (errno(system.getsockname(sockfd, addr, addrlen))) { - 0 => return, - else => |err| return unexpectedErrno(err), +pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { + const rc = system.getsockname(sock, addr, addrlen); + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEINVAL => return error.SocketNotBound, + else => |err| return windows.unexpectedWSAError(err), + } + } + return; + } else { + switch (errno(rc)) { + 0 => return, + else => |err| return unexpectedErrno(err), - EBADF => unreachable, // always a race condition - EFAULT => unreachable, - EINVAL => unreachable, // invalid parameters - ENOTSOCK => unreachable, - ENOBUFS => return error.SystemResources, + EBADF => unreachable, // always a race condition + EFAULT => unreachable, + EINVAL => unreachable, // invalid parameters + ENOTSOCK => return error.FileDescriptorNotASocket, + ENOBUFS => return error.SystemResources, + } } } @@ -3041,9 +3148,9 @@ pub const ConnectError = error{ /// Initiate a connection on a socket. /// If `sockfd` is opened in non blocking mode, the function will /// return error.WouldBlock when EAGAIN or EINPROGRESS is received. -pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { +pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { if (builtin.os.tag == .windows) { - const rc = windows.ws2_32.connect(sockfd, sock_addr, len); + const rc = windows.ws2_32.connect(sock, sock_addr, @intCast(i32, len)); if (rc == 0) return; switch (windows.ws2_32.WSAGetLastError()) { .WSAEADDRINUSE => return error.AddressInUse, @@ -3066,7 +3173,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con } while (true) { - switch (errno(system.connect(sockfd, sock_addr, len))) { + switch (errno(system.connect(sock, sock_addr, len))) { 0 => return, EACCES => return error.PermissionDenied, EPERM => return error.PermissionDenied, @@ -3921,32 +4028,49 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { } } -fn setSockFlags(fd: fd_t, flags: u32) !void { +fn setSockFlags(sock: socket_t, flags: u32) !void { if ((flags & SOCK_CLOEXEC) != 0) { - var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) { - error.FileBusy => unreachable, - error.Locked => unreachable, - else => |e| return e, - }; - fd_flags |= FD_CLOEXEC; - _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) { - error.FileBusy => unreachable, - error.Locked => unreachable, - else => |e| return e, - }; + if (builtin.os.tag == .windows) { + // TODO: Find out if this is supported for sockets + } else { + var fd_flags = fcntl(sock, F_GETFD, 0) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + fd_flags |= FD_CLOEXEC; + _ = fcntl(sock, F_SETFD, fd_flags) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + } } if ((flags & SOCK_NONBLOCK) != 0) { - var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) { - error.FileBusy => unreachable, - error.Locked => unreachable, - else => |e| return e, - }; - fl_flags |= O_NONBLOCK; - _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) { - error.FileBusy => unreachable, - error.Locked => unreachable, - else => |e| return e, - }; + if (builtin.os.tag == .windows) { + var mode: c_ulong = 1; + if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + // TODO: handle more errors + else => |err| return windows.unexpectedWSAError(err), + } + } + } else { + var fl_flags = fcntl(sock, F_GETFL, 0) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + fl_flags |= O_NONBLOCK; + _ = fcntl(sock, F_SETFL, fl_flags) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + } } } @@ -4544,6 +4668,8 @@ pub const SendError = error{ /// The local end has been shut down on a connection oriented socket. In this case, the /// process will also receive a SIGPIPE unless MSG_NOSIGNAL is set. BrokenPipe, + + FileDescriptorNotASocket, } || UnexpectedError; /// Transmit a message to another socket. @@ -4573,7 +4699,7 @@ pub const SendError = error{ /// possible to send more data. pub fn sendto( /// The file descriptor of the sending socket. - sockfd: fd_t, + sockfd: socket_t, /// Message to send. buf: []const u8, flags: u32, @@ -4582,26 +4708,43 @@ pub fn sendto( ) SendError!usize { while (true) { const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen); - switch (errno(rc)) { - 0 => return @intCast(usize, rc), - EACCES => return error.AccessDenied, - EAGAIN => return error.WouldBlock, - EALREADY => return error.FastOpenAlreadyInProgress, - EBADF => unreachable, // always a race condition - ECONNRESET => return error.ConnectionResetByPeer, - EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. - EFAULT => unreachable, // An invalid user space address was specified for an argument. - EINTR => continue, - EINVAL => unreachable, // Invalid argument passed. - EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified - EMSGSIZE => return error.MessageTooBig, - ENOBUFS => return error.SystemResources, - ENOMEM => return error.SystemResources, - ENOTCONN => unreachable, // The socket is not connected, and no target has been given. - ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. - EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. - EPIPE => return error.BrokenPipe, - else => |err| return unexpectedErrno(err), + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSAEACCES => return error.AccessDenied, + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAEMSGSIZE => return error.MessageTooBig, + .WSAENOBUFS => return error.SystemResources, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + // TODO: handle more errors + else => |err| return windows.unexpectedWSAError(err), + } + } else { + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + + EACCES => return error.AccessDenied, + EAGAIN => return error.WouldBlock, + EALREADY => return error.FastOpenAlreadyInProgress, + EBADF => unreachable, // always a race condition + ECONNRESET => return error.ConnectionResetByPeer, + EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. + EFAULT => unreachable, // An invalid user space address was specified for an argument. + EINTR => continue, + EINVAL => unreachable, // Invalid argument passed. + EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified + EMSGSIZE => return error.MessageTooBig, + ENOBUFS => return error.SystemResources, + ENOMEM => return error.SystemResources, + ENOTCONN => unreachable, // The socket is not connected, and no target has been given. + ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. + EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. + EPIPE => return error.BrokenPipe, + else => |err| return unexpectedErrno(err), + } } } } @@ -4627,7 +4770,7 @@ pub fn sendto( /// possible to send more data. pub fn send( /// The file descriptor of the sending socket. - sockfd: fd_t, + sockfd: socket_t, buf: []const u8, flags: u32, ) 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 } pub const PollError = error{ + /// The network subsystem has failed. + NetworkSubsystemFailed, + /// The kernel had no space to allocate file descriptor tables. SystemResources, } || UnexpectedError; @@ -5049,14 +5195,29 @@ pub const PollError = error{ pub fn poll(fds: []pollfd, timeout: i32) PollError!usize { while (true) { const rc = system.poll(fds.ptr, fds.len, timeout); - switch (errno(rc)) { - 0 => return @intCast(usize, rc), - EFAULT => unreachable, - EINTR => continue, - EINVAL => unreachable, - ENOMEM => return error.SystemResources, - else => |err| return unexpectedErrno(err), + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENOBUFS => return error.SystemResources, + // TODO: handle more errors + else => |err| return windows.unexpectedWSAError(err), + } + } else { + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + EFAULT => unreachable, + EINTR => continue, + EINVAL => unreachable, + ENOMEM => return error.SystemResources, + else => |err| return unexpectedErrno(err), + } } + unreachable; } } @@ -5071,12 +5232,30 @@ pub const RecvFromError = error{ /// Could not allocate kernel memory. SystemResources, + + ConnectionResetByPeer, + + /// The socket has not been bound. + SocketNotBound, + + /// The UDP message was too big for the buffer and part of it has been discarded + MessageTooBig, + + /// The network subsystem has failed. + NetworkSubsystemFailed, + + /// The socket is not connected (connection-oriented sockets only). + SocketNotConnected, } || UnexpectedError; +pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize { + return recvfrom(sock, buf, flags, null, null); +} + /// If `sockfd` is opened in non blocking mode, the function will /// return error.WouldBlock when EAGAIN is received. pub fn recvfrom( - sockfd: fd_t, + sockfd: socket_t, buf: []u8, flags: u32, src_addr: ?*sockaddr, @@ -5084,18 +5263,36 @@ pub fn recvfrom( ) RecvFromError!usize { while (true) { const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen); - switch (errno(rc)) { - 0 => return @intCast(usize, rc), - EBADF => unreachable, // always a race condition - EFAULT => unreachable, - EINVAL => unreachable, - ENOTCONN => unreachable, - ENOTSOCK => unreachable, - EINTR => continue, - EAGAIN => return error.WouldBlock, - ENOMEM => return error.SystemResources, - ECONNREFUSED => return error.ConnectionRefused, - else => |err| return unexpectedErrno(err), + if (builtin.os.tag == .windows) { + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAEINVAL => return error.SocketNotBound, + .WSAEMSGSIZE => return error.MessageTooBig, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENOTCONN => return error.SocketNotConnected, + .WSAEWOULDBLOCK => return error.WouldBlock, + // TODO: handle more errors + else => |err| return windows.unexpectedWSAError(err), + } + } else { + return @intCast(usize, rc); + } + } else { + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + EBADF => unreachable, // always a race condition + EFAULT => unreachable, + EINVAL => unreachable, + ENOTCONN => unreachable, + ENOTSOCK => unreachable, + EINTR => continue, + EAGAIN => return error.WouldBlock, + ENOMEM => return error.SystemResources, + ECONNREFUSED => return error.ConnectionRefused, + else => |err| return unexpectedErrno(err), + } } } } |
