diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 1a969210aa78..5941acb5936d 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -5826,7 +5826,20 @@ pub fn ppoll(fds: []pollfd, timeout: ?*const timespec, mask: ?*const sigset_t) P } } -pub const RecvFromError = error{ +pub const RecvError = error{ + /// Returned when socket is AF.UNIX and the given path has a symlink loop. + SymLinkLoop, + + /// Returned when socket is AF.UNIX and the given path length exceeds `max_path_bytes` bytes. + NameTooLong, + + /// Returned when socket is AF.UNIX and the given path does not point to an existing file. + FileNotFound, + NotDir, + + /// Network is unreachable. + NetworkUnreachable, + /// The socket is marked nonblocking and the requested operation would block, and /// there is no global event loop configured. WouldBlock, @@ -5838,27 +5851,93 @@ pub const RecvFromError = error{ /// Could not allocate kernel memory. SystemResources, + ///The connection was reset by the peer ConnectionResetByPeer, - Timeout, + + ///Operation now in progress.A blocking operation is currently executing. + BlockingOperationInProgress, + + ///Connection timed out + ConnectionTimedOut, /// The socket has not been bound. SocketNotBound, + ///Software caused connection abort. An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error. + ConnectionAborted, + + /// The file descriptor sockfd does not refer to a socket. + FileDescriptorNotASocket, + + /// The socket is not of a type that supports the recv() operation. + OperationNotSupported, + /// The UDP message was too big for the buffer and part of it has been discarded - MessageOversize, + MessageTooBig, /// The network subsystem has failed. - NetworkDown, + NetworkSubsystemFailed, /// The socket is not connected (connection-oriented sockets only). - SocketUnconnected, + SocketNotConnected, - /// The other end closed the socket unexpectedly or a read is executed on a shut down socket - BrokenPipe, + /// Already connected + AlreadyConnected, +} || UnexpectedError; + +pub const RecvFromError = RecvError || error{ + /// The passed address didn't have the correct address family in its sa_family field. + AddressFamilyNotSupported, + + /// The socket is not connected (connection-oriented sockets only). + AddressNotAvailable, + + /// The destination address is not reachable by the bound address. + UnreachableAddress, } || UnexpectedError; -pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize { - return recvfrom(sock, buf, flags, null, null); +/// Receive messages from a socket. +/// The `recv` call may be used only when the socket is in a connected state (so that the intended +/// recipient is known). The only difference between `recv` and `read` is the presence of +/// flags. With a zero flags argument, `recv` is equivalent to `read`. Also, the following +/// call +/// +/// recv(sockfd, buf, flags); +/// +/// is equivalent to +/// +/// recvfrom(sockfd, buf, flags, NULL, NULL); +/// +/// If recvfrom() is used on a connection-mode (`SOCK.STREAM`, `SOCK.SEQPACKET`) socket, the arguments +/// `src_addr` and `addrlen` are asserted to be `null` and `null` respectively, and asserted +/// that the socket was actually connected. +/// Otherwise, the address of the source is given by `src_addr` with `addrlen` specifying its size. +/// +/// If the message is too long to pass atomically through the underlying protocol, +/// `RecvError.MessageTooBig` is returned, and the message is not transmitted. +/// +/// When the message does not fit into the recv buffer of the socket, `recv` normally blocks, +/// unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail +/// with `RecvError.WouldBlock`. The `select` call may be used to determine when it is +/// possible to receive more data. +pub fn recv( + /// The file descriptor of the sending socket. + sock: socket_t, + buf: []u8, + flags: u32, +) RecvError!usize { + return recvfrom(sock, buf, flags, null, null) catch |err| switch (err) { + error.AddressFamilyNotSupported => unreachable, + error.SymLinkLoop => unreachable, + error.NameTooLong => unreachable, + error.FileNotFound => unreachable, + error.NotDir => unreachable, + error.NetworkUnreachable => unreachable, + error.AddressNotAvailable => unreachable, + error.SocketNotConnected => unreachable, + error.UnreachableAddress => unreachable, + else => |e| return e, + }; } /// If `sockfd` is opened in non blocking mode, the function will @@ -5871,39 +5950,48 @@ pub fn recvfrom( addrlen: ?*socklen_t, ) RecvFromError!usize { while (true) { - const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen); if (native_os == .windows) { + const rc = windows.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen); if (rc == windows.ws2_32.SOCKET_ERROR) { switch (windows.ws2_32.WSAGetLastError()) { - .NOTINITIALISED => unreachable, - .ECONNRESET => return error.ConnectionResetByPeer, - .EINVAL => return error.SocketNotBound, - .EMSGSIZE => return error.MessageOversize, - .ENETDOWN => return error.NetworkDown, - .ENOTCONN => return error.SocketUnconnected, - .EWOULDBLOCK => return error.WouldBlock, - .ETIMEDOUT => return error.Timeout, - // TODO: handle more errors + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAEFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small. + .WSAEINTR => continue, + .WSAEINPROGRESS => return error.BlockingOperationInProgress, + .WSAEINVAL => return error.SocketNotBound, + .WSAEISCONN => return error.AlreadyConnected, + .WSAENETRESET => return error.ConnectionResetByPeer, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => return error.OperationNotSupported, + .WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH. + .WSAEWOULDBLOCK => return error.WouldBlock, + .WSAEMSGSIZE => return error.MessageTooBig, + .WSAETIMEDOUT => return error.ConnectionTimedOut, + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAENOTCONN => return error.SocketNotConnected, + .WSAECONNABORTED => return error.ConnectionAborted, + // TODO: test all errors else => |err| return windows.unexpectedWSAError(err), } } else { return @intCast(rc); } } else { + const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .BADF => unreachable, // always a race condition .FAULT => unreachable, - .INVAL => unreachable, - .NOTCONN => return error.SocketUnconnected, - .NOTSOCK => unreachable, + .INVAL => return error.SocketNotBound, + .NOTCONN => return error.SocketNotConnected, + .NOTSOCK => return error.FileDescriptorNotASocket, .INTR => continue, .AGAIN => return error.WouldBlock, .NOMEM => return error.SystemResources, .CONNREFUSED => return error.ConnectionRefused, .CONNRESET => return error.ConnectionResetByPeer, - .TIMEDOUT => return error.Timeout, - .PIPE => return error.BrokenPipe, + .TIMEDOUT => return error.ConnectionTimedOut, else => |err| return unexpectedErrno(err), } }