Last active
March 10, 2021 07:52
-
-
Save pushkarnk/fa4fb09ba1f816ef02539f344e826e39 to your computer and use it in GitHub Desktop.
reproducer: poll returns POLLIN for fd on which out-of-band data arrived
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _XOPEN_SOURCE_EXTENDED 1 | |
#define _OPEN_THREADS | |
#include <pthread.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/ioctl.h> | |
#include <sys/socket.h> | |
#include <sys/time.h> | |
#include <netinet/in.h> | |
#include <errno.h> | |
#include <poll.h> | |
#include <arpa/inet.h> | |
#define SERVER_PORT 12345 | |
#define FALSE 0 | |
#define TRUE 1 | |
void* client(void* args) { | |
int sock_fd, i; | |
struct sockaddr_in servaddr, cli; | |
char d = 0xff, buffer[512]; | |
sleep(3); | |
sock_fd = socket(AF_INET, SOCK_STREAM, 0); | |
if (sock_fd == -1) { | |
printf("client: socket creation failed\n"); | |
exit(1); | |
} | |
bzero(&servaddr, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); | |
servaddr.sin_port = htons(SERVER_PORT); | |
if (connect(sock_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0) { | |
printf("client: connection to server failed\n"); | |
exit(1); | |
} | |
bzero(buffer, sizeof(buffer)); | |
for (i=0; i<512; i++) | |
buffer[i] = 1; | |
write(sock_fd, buffer, sizeof(buffer)); | |
send(sock_fd, &d, 1, MSG_OOB); | |
/*write(sock_fd, buffer, sizeof(buffer)); */ | |
/* we don't actually intend to read, we just want to block here */ | |
bzero(buffer, sizeof(buffer)); | |
read(sock_fd, buffer, sizeof(buffer)); | |
/* we must not reach here */ | |
printf(" client: exiting\n"); | |
} | |
void main (int argc, char *argv[]) | |
{ | |
int len, rc, on = 1; | |
int listen_sd = -1, new_sd = -1; | |
int end_server = FALSE; | |
int timeout; | |
int nfds = 1, current_size = 0, i, j; | |
int n_spurious_reads = 0; | |
char buffer[100]; | |
struct sockaddr_in addr; | |
struct pollfd fds[200]; | |
pthread_t tid; | |
listen_sd = socket(AF_INET, SOCK_STREAM, 0); | |
if (listen_sd < 0) { | |
perror("socket() failed"); | |
exit(-1); | |
} | |
if (ioctl(listen_sd, FIONBIO, (char *)&on) < 0) { | |
perror("ioctl() failed"); | |
close(listen_sd); | |
exit(-1); | |
} | |
memset(&addr, 0, sizeof(addr)); | |
addr.sin_family = AF_INET; | |
addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
addr.sin_port = htons(SERVER_PORT); | |
if (bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | |
perror("bind() failed"); | |
close(listen_sd); | |
exit(-1); | |
} | |
if (listen(listen_sd, 32) < 0) { | |
perror("listen() failed"); | |
close(listen_sd); | |
exit(-1); | |
} | |
memset(fds, 0 , sizeof(fds)); | |
fds[0].fd = listen_sd; | |
fds[0].events = POLLIN; | |
timeout = (60 * 1000); | |
pthread_create(&tid, NULL, client, "Client 1"); | |
do | |
{ | |
rc = poll(fds, nfds, timeout); | |
if (rc < 0) { | |
perror(" poll() failed"); | |
break; | |
} | |
if (rc == 0) { | |
printf(" server: poll() timed out. End program.\n"); | |
break; | |
} | |
current_size = nfds; | |
for (i = 0; i < current_size; i++) { | |
if(fds[i].revents == 0) | |
continue; | |
if(fds[i].revents != POLLIN && fds[i].revents != POLLRDNORM) { | |
printf(" Error! revents = %d\n", fds[i].revents); | |
end_server = TRUE; | |
break; | |
} | |
if (fds[i].fd == listen_sd) { | |
printf(" server: Listening socket is readable\n"); | |
do { | |
new_sd = accept(listen_sd, NULL, NULL); | |
if (new_sd < 0) { | |
if (errno != EWOULDBLOCK) { | |
perror(" accept() failed"); | |
end_server = TRUE; | |
} | |
break; | |
} | |
printf(" server: New incoming connection - %d\n", new_sd); | |
fds[nfds].fd = new_sd; | |
fds[nfds].events = POLLIN; | |
nfds++; | |
} while (new_sd != -1); | |
} else { | |
rc = read(fds[i].fd, buffer, sizeof(buffer)); | |
if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | |
printf(" server: read() returned %d, errno = %d, 0 bytes received\n", rc, errno); | |
if (++n_spurious_reads > 10) { | |
printf(" Too many spurious reads. Test failed.\n"); | |
end_server = TRUE; | |
break; | |
} | |
} else if (rc < 0) { | |
printf(" server: read failed with errno = %d\n", errno); | |
} else { | |
len = rc; | |
printf(" server: %d bytes received\n", len); | |
} | |
} | |
} | |
} while (end_server == FALSE); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment