songtzu songtzu - 3 months ago 22
Linux Question

socket fin after syn ack on centos 7

I write a tcp server with epoll, it works right on Ubuntu, but strange things happens on CentOS7 occasional.

client a try to connect to server b, the connection was build,
the port for client is 59298, port for server is 8802, and the socketfd at server is 16.

[syn]



[syn,ack]



[ack]



at the mean time the server read event with return value zero, with the same sockfd, which is 16, JUST the same as the connection build before, tell the connection between a and b was closed. server send a package of [rst,ack] to client with different port, which is 59191. why this happens ? is it a bug of centos kernel?

my code is very similar to this below.

#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;

/* Set up listening socket, 'listen_sock' (socket(),
bind(), listen()) */

epollfd = epoll_create(10);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}

ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}

for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}

for (n = 0; n < nfds; ++n) {
if (events[n].data.fd == listen_sock) {
conn_sock = accept(listen_sock,
(struct sockaddr *) &local, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
do_use_fd(events[n].data.fd);
}
}
}


here is my tcpdump result.
enter image description here

Answer

I got the reason after read man epoll. it happens due to unsuitable code.

 epoll_ctl(epollfd_, EPOLL_CTL_DEL, sockfd, &ev)

it seems there is few correct usage sample about epoll on github.