aboutsummaryrefslogblamecommitdiffstats
path: root/recv.c
blob: 03985ba1924aa7c94f2ed34d6c7da1f6efac3bd0 (plain) (tree)



























































































































                                                                                                                        
/* See LICENSE file for copyright and license details. */
#include "internal.h"


void
liberror_recv_failed(int fd, void *buf, size_t n, int flags, const char *fname)
{
	const char *desc;
	int saved_errno, val;
	struct timeval tv;
	switch (errno) {
#if defined(EAGAIN)
	case EAGAIN:
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EAGAIN != EWOULDBLOCK)
	case EWOULDBLOCK:
#endif
#if defined(EAGAIN) || defined(EWOULDBLOCK)
		saved_errno = errno;
		if (flags & MSG_OOB) {
			desc = "Attempting to receive in nonblocking mode but the operation would block, "
			       "attempting to receive with time out and the operation timed out "
			       "or the socket does not support blocking to await out-of-band data";
			if (flags & MSG_DONTWAIT) {
			msg_oob_nonblocking:
				desc = "Attempting to receive in nonblocking mode but the operation would block or"
				       " the socket does not support blocking to await out-of-band data";
			} else if ((val = fcntl(fd, F_GETFL)) < 0) {
				/* Do nothing */
			} else if (val & O_NONBLOCK) {
				goto msg_oob_nonblocking;
			} else if (getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &(socklen_t){(socklen_t)sizeof(tv)}) ||
			           tv.tv_sec || tv.tv_usec) {
				desc = "Attempting to receive with time out and the operation timed out or"
				       " the socket does not support blocking to await out-of-band data";
			} else {
				desc = "The socket does not support blocking to await out-of-band data";
			}
		} else {
			desc = "Attempting to receive in nonblocking mode but the operation would block "
			       "or attempting to receive with time out and the operation timed out";
			if (flags & MSG_DONTWAIT) {
			no_msg_oob_nonblocking:
				desc = "Attempting to receive in nonblocking mode but the operation would block";
			} else if ((val = fcntl(fd, F_GETFL)) < 0) {
				/* Do nothing */
			} else if (val & O_NONBLOCK) {
				goto no_msg_oob_nonblocking;
			} else if (!getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &(socklen_t){(socklen_t)sizeof(tv)}) &&
			           !tv.tv_sec && !tv.tv_usec) {
				desc = "Attempting to receive with time out and the operation timed out";
			}
		}
		errno = saved_errno;
		break;
#endif
	case EBADF:
		if (fd < 0)
			desc = "Negative file descriptor number specified";
		else
			desc = "Unassigned file descriptor number specified";
		break;
	case ECONNREFUSED:
		desc = "The remote host refused to allow the network connection";
		break;
	case ECONNRESET:
		desc = "The connection was forcibly closed by a peer";
		break;
	case EFAULT:
		desc = "Invalid user space address specified in the second argument";
		break;
	case EINTR:
		desc = "System call was interrupted by a signal or machine suspension";
		break;
	case EINVAL:
		if (fd < 0)
			desc = "Negative file descriptor number specified";
		else if ((flags & ~(MSG_PEEK | MSG_WAITALL)) == MSG_OOB)
			desc = "No out-of-band data is available";
		else if (flags & MSG_OOB)
			desc = "No out-of-band data is available or non-existing flag is specified";
		else
			desc = "Non-existing flag is specified";
		break;
	case EIO:
		desc = "An I/O error occurred while reading from or writing to the file system";
		break;
	case ENOBUFS:
		desc = "Insufficient resource available in the system to perform the operation";
		break;
	case ENOMEM:
		desc = "Out of memory";
		break;
	case ENOTCONN:
		desc = "The socket is not connected";
		break;
	case ENOTSOCK:
		desc = "The file descriptor refer to a non-socket file";
		break;
	case EOPNOTSUPP:
		desc = "A flag that is not supported for the socket protocol is specified";
		break;
	case ETIMEDOUT:
		desc = "The connection timed out during connection establishment, "
		       "or due to a transmission timeout on active connection";
		break;
	default:
		desc = "";
		break;
	}
	liberror_libc_set_error_one_file(desc, "recv", "Socket file", fd, fname);
}


ssize_t
liberror_recv(int fd, void *buf, size_t n, int flags, const char *fname)
{
	ssize_t r = recv(fd, buf, n, flags);
	if (r >= 0)
		return r;
	liberror_save_backtrace(NULL);
	liberror_recv_failed(fd, buf, n, flags, fname);
	return -1;
}