Skip to content

Instantly share code, notes, and snippets.

@pushkarnk
Last active March 10, 2021 07:52
Show Gist options
  • Save pushkarnk/fa4fb09ba1f816ef02539f344e826e39 to your computer and use it in GitHub Desktop.
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
#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