aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-10-22 16:59:15 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-10-22 16:59:15 -0700
commit569f7ce49ea778864636316cfe41acb3944cf3d4 (patch)
treea54f7eb5f3e57b5d774bb05d7f5c663efb2f52b8 /lib/std/os.zig
parentddd39b994b1eb9751d06227c6db02f15a5f71e9f (diff)
parent127fa8009011e19d552ffdd834c6a607498f1c1e (diff)
downloadzig-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.zig481
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),
+ }
}
}
}