[#3709] Ensure all data is read from socket when EPOLLRDUP is received
Motivation: When EPOLLRDHUP is received we need to try to read at least one time to ensure that we read all pending data from the socket. Otherwise we may loose data. Modifications: - Ensure we read all data from socket - Ensure file descriptor is closed on doClose() even if doDeregister() throws an Exception. - Only handle either EPOLLRDHUP or EPOLLIN as only one is needed to detect connection reset. Result: No more data loss on connection reset.
This commit is contained in:
parent
b3abd58b05
commit
08e4b076be
@ -99,12 +99,14 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
@Override
|
@Override
|
||||||
protected void doClose() throws Exception {
|
protected void doClose() throws Exception {
|
||||||
active = false;
|
active = false;
|
||||||
|
try {
|
||||||
// deregister from epoll now
|
// deregister from epoll now
|
||||||
doDeregister();
|
doDeregister();
|
||||||
|
} finally {
|
||||||
FileDescriptor fd = fileDescriptor;
|
// Ensure the file descriptor is closed in all cases.
|
||||||
fd.close();
|
FileDescriptor fd = fileDescriptor;
|
||||||
|
fd.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -765,11 +765,14 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void epollRdHupReady() {
|
void epollRdHupReady() {
|
||||||
// Just call closeOnRead(). There is no need to trigger a read as this
|
if (isActive()) {
|
||||||
// will result in an IOException anyway.
|
// If it is still active, we need to call epollInReady as otherwise we may miss to
|
||||||
//
|
// read pending data from the underyling file descriptor.
|
||||||
// See https://github.com/netty/netty/issues/3539
|
// See https://github.com/netty/netty/issues/3709
|
||||||
closeOnRead(pipeline());
|
epollInReady();
|
||||||
|
} else {
|
||||||
|
closeOnRead(pipeline());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -310,14 +310,15 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
final long ev = events.events(i);
|
final long ev = events.events(i);
|
||||||
|
|
||||||
AbstractEpollChannel ch = channels.get(fd);
|
AbstractEpollChannel ch = channels.get(fd);
|
||||||
if (ch != null && ch.isOpen()) {
|
if (ch != null) {
|
||||||
|
|
||||||
AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe();
|
AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe();
|
||||||
|
|
||||||
// We need to check if the channel is still open before try to trigger the
|
// First check if EPOLLIN was set, in this case we do not need to check for
|
||||||
// callbacks.
|
// EPOLLRDHUP as EPOLLIN will handle connection-reset case as well.
|
||||||
// See https://github.com/netty/netty/issues/3443
|
if ((ev & Native.EPOLLIN) != 0) {
|
||||||
if ((ev & Native.EPOLLRDHUP) != 0 && ch.isOpen()) {
|
// Something is ready to read, so consume it now
|
||||||
|
unsafe.epollInReady();
|
||||||
|
} else if ((ev & Native.EPOLLRDHUP) != 0) {
|
||||||
unsafe.epollRdHupReady();
|
unsafe.epollRdHupReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,11 +326,6 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
// force flush of data as the epoll is writable again
|
// force flush of data as the epoll is writable again
|
||||||
unsafe.epollOutReady();
|
unsafe.epollOutReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ev & Native.EPOLLIN) != 0 && ch.isOpen()) {
|
|
||||||
// Something is ready to read, so consume it now
|
|
||||||
unsafe.epollInReady();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// We received an event for an fd which we not use anymore. Remove it from the epoll_event set.
|
// We received an event for an fd which we not use anymore. Remove it from the epoll_event set.
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user