// Jeremy M. Rifkin 11.25.19 // Demonstrate that EAGAIN/EWOULDBLOCK can be triggered on accept(2) by a recv timeout #include #include #include #include #include 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; }