linux-man.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeremy Rifkin <rifkin.jer@gmail.com>
To: mtk.manpages@gmail.com
Cc: linux-man@vger.kernel.org, netdev@vger.kernel.org
Subject: [patch] accept.2: Added information about what can cause EAGAIN and EWOULDBLOCK errors
Date: Tue, 26 Nov 2019 15:29:30 -0700	[thread overview]
Message-ID: <CABMFubf=Ht7xFaN+9jiddDj08D150jwHpio8i09KHCSD_9bK=Q@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1620 bytes --]

Hello,
According to the accept.2 man page, EAGAIN and EWOULDBLOCK errors can occur when
"The socket is marked nonblocking and no connections are present to be
accepted". I have found that these errors can also occur when a receive timeout
has been set on the socket and the timeout expires before a connection can be
accepted. This appears to be the same behavior of the recv system call whose man
page states that EAGAIN and EWOULDBLOCK occur when "The socket is marked
nonblocking and the receive operation would block, or a receive timeout had been
set and the timeout expired before data was received."

I've included a test program to demonstrate that accept will fail with exit code
EAGAIN/EWOULDBLOCK when a receive timeout is set and the timeout expires.

This patch applies to the latest version man-pages, 5.04. I have amended
accept.2 to include this second reason why EAGAIN/EWOULDBLOCK can
occur. I have tried to use similar wording to that of the recv.2 man page.

======== Begin Diff ========

diff --git a/man2/accept.2 b/man2/accept.2
index a4bebd214..63e90a5e6 100644
--- a/man2/accept.2
+++ b/man2/accept.2
@@ -208,7 +208,9 @@ and
 .BR EAGAIN " or " EWOULDBLOCK
 .\" Actually EAGAIN on Linux
 The socket is marked nonblocking and no connections are
-present to be accepted.
+present to be accepted, or a receive timeout has been
+set and the timeout expired before a new connection
+was available to be accepted.
 POSIX.1-2001 and POSIX.1-2008
 allow either error to be returned for this case,
 and do not require these constants to have the same value,

========= End Diff =========

- Jeremy Rifkin

[-- Attachment #2: accept2test.c --]
[-- Type: text/plain, Size: 3012 bytes --]

// Jeremy M. Rifkin 11.25.19
// Demonstrate that EAGAIN/EWOULDBLOCK can be triggered on accept(2) by a recv timeout
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

void fail(char* format) {
	fprintf(stderr, format, errno);
	fflush(stderr);
	exit(1);
}

int main (int argc, char *argv[]) {
	int err;
	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if(socketfd < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to create socket (errno: %d)... This shouldn't have "
			"happened.\n");

	// Configure socket
	struct sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(0); // port 0 for random port
	server.sin_addr.s_addr = htonl(INADDR_ANY);

	// Set reuseaddr
	int opt = 1;
	err = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	if(err < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to set socket reuseaddr (errno: %d)... This shouldn't "
			"have happened.\n");

	// Configure timeout
	struct timeval timeout;
	timeout.tv_sec = 4; // 4 second timeout
	timeout.tv_usec = 0;
	err = setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
	if(err < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to set socket recv timeout (errno: %d)... This "
			"shouldn't have happened.\n");

	// Bind the socket
	err = bind(socketfd, (struct sockaddr*) &server, sizeof(server));
	if(err < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to bind socket (errno: %d)... This shouldn't have "
			"happened.\n");

	// Mark socket as passive.
	err = listen(socketfd, 128);
	if(err < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to listen on socket (errno: %d)... This shouldn't "
			"have happened.\n");

	// Get port
	// Serves as both a check and also accommodates for "random" ports.
	struct sockaddr_in addr;
	socklen_t addr_len = sizeof(addr);
	err = getsockname(socketfd, (struct sockaddr*)&addr, &addr_len);
	if(err < 0)
		fail("\x1b[1;35mError:\x1b[0m failed to get socket address (errno: %d)... This shouldn't "
			"have happened.\n");
	printf("Socket listening on port %d\n", ntohs(addr.sin_port));
	
	// Demonstrate recv timeout failure
	printf("\nA 4 second recv timeout has been set on the socket.\n");
	printf("The program will now attempt to accept connections.\n");
	printf("It should fail with error EAGAIN/EWOULDBLOCK roughly\n");
	printf("every 4 seconds.\n\n");
	while(1) {
		struct sockaddr_in client;
		socklen_t client_len = sizeof(client);
		int clientfd = accept(socketfd, (struct sockaddr*)&client, &client_len);

		if(clientfd < 0) {
			if(errno == EAGAIN)
				fprintf(stderr, "\x1b[1;35mError:\x1b[0m Socket failed to accept with error EAGAIN."
					"\n");
			else if(errno == EWOULDBLOCK)
				fprintf(stderr, "\x1b[1;35mError:\x1b[0m Socket failed to accept with error "
					"EWOULDBLOCK.\n");
			else
				fprintf(stderr, "\x1b[1;35mError:\x1b[0m failed to establish new connection "
					"(errno: %d)... This shouldn't have happened.\n",
					errno);
			fflush(stderr);
		}
	}

	return 0;
}


                 reply	other threads:[~2019-11-26 22:29 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABMFubf=Ht7xFaN+9jiddDj08D150jwHpio8i09KHCSD_9bK=Q@mail.gmail.com' \
    --to=rifkin.jer@gmail.com \
    --cc=linux-man@vger.kernel.org \
    --cc=mtk.manpages@gmail.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).