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
// 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; }