Java Code Examples for io.netty.channel.ChannelPipeline#fireChannelRead()

The following examples show how to use io.netty.channel.ChannelPipeline#fireChannelRead() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: AbstractXnioSocketChannel.java    From netty-xnio-transport with Apache License 2.0 6 votes vote down vote up
private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close) {
    if (byteBuf != null) {
        if (byteBuf.isReadable()) {
            pipeline.fireChannelRead(byteBuf);
        } else {
            try {
                byteBuf.release();
            } catch (IllegalReferenceCountException ignore) {
                // ignore as it may be released already
            }
        }
    }
    pipeline.fireChannelReadComplete();
    pipeline.fireExceptionCaught(cause);
    if (close || cause instanceof IOException) {
        closeOnRead();
    }
}
 
Example 2
Source File: AbstractOioByteChannel.java    From netty-4.1.22 with Apache License 2.0 6 votes vote down vote up
private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close,
        RecvByteBufAllocator.Handle allocHandle) {
    if (byteBuf != null) {
        if (byteBuf.isReadable()) {
            readPending = false;
            pipeline.fireChannelRead(byteBuf);
        } else {
            byteBuf.release();
        }
    }
    allocHandle.readComplete();
    pipeline.fireChannelReadComplete();
    pipeline.fireExceptionCaught(cause);
    if (close || cause instanceof IOException) {
        closeOnRead(pipeline);
    }
}
 
Example 3
Source File: AbstractEpollStreamChannel.java    From netty-4.1.22 with Apache License 2.0 6 votes vote down vote up
private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close,
        EpollRecvByteAllocatorHandle allocHandle) {
    if (byteBuf != null) {
        if (byteBuf.isReadable()) {
            readPending = false;
            pipeline.fireChannelRead(byteBuf);
        } else {
            byteBuf.release();
        }
    }
    allocHandle.readComplete();
    pipeline.fireChannelReadComplete();
    pipeline.fireExceptionCaught(cause);
    if (close || cause instanceof IOException) {
        shutdownInput(false);
    }
}
 
Example 4
Source File: LocalServerChannel.java    From netty4.0.27Learn with Apache License 2.0 6 votes vote down vote up
@Override
protected void doBeginRead() throws Exception {
    if (acceptInProgress) {
        return;
    }

    Queue<Object> inboundBuffer = this.inboundBuffer;
    if (inboundBuffer.isEmpty()) {
        acceptInProgress = true;
        return;
    }

    ChannelPipeline pipeline = pipeline();
    for (;;) {
        Object m = inboundBuffer.poll();
        if (m == null) {
            break;
        }
        pipeline.fireChannelRead(m);
    }
    pipeline.fireChannelReadComplete();
}
 
Example 5
Source File: AbstractNioByteChannel.java    From netty-4.1.22 with Apache License 2.0 6 votes vote down vote up
private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close,
        RecvByteBufAllocator.Handle allocHandle) {
    if (byteBuf != null) {
        if (byteBuf.isReadable()) {
            readPending = false;
            pipeline.fireChannelRead(byteBuf);
        } else {
            byteBuf.release();
        }
    }
    allocHandle.readComplete();
    pipeline.fireChannelReadComplete();
    pipeline.fireExceptionCaught(cause);
    if (close || cause instanceof IOException) {
        closeOnRead(pipeline);
    }
}
 
Example 6
Source File: LocalChannel.java    From netty4.0.27Learn with Apache License 2.0 5 votes vote down vote up
@Override
public void run() {
    ChannelPipeline pipeline = pipeline();
    for (;;) {
        Object m = inboundBuffer.poll();
        if (m == null) {
            break;
        }
        pipeline.fireChannelRead(m);
    }
    pipeline.fireChannelReadComplete();
}
 
Example 7
Source File: Utils.java    From kcp-netty with MIT License 5 votes vote down vote up
static void fireChannelRead(Channel ch, CodecOutputList<ByteBuf> bufList) {
    ChannelPipeline pipeline = ch.pipeline();
    int size = bufList.size();
    if (size <= 0) {
        return;
    }
    for (int i = 0; i < size; i++) {
        ByteBuf msg = bufList.getUnsafe(i);
        pipeline.fireChannelRead(msg);
    }
    pipeline.fireChannelReadComplete();
}
 
Example 8
Source File: VirtualServerChannel.java    From quarkus with Apache License 2.0 5 votes vote down vote up
private void readInbound() {
    RecvByteBufAllocator.Handle handle = unsafe().recvBufAllocHandle();
    handle.reset(config());
    ChannelPipeline pipeline = pipeline();
    do {
        Object m = inboundBuffer.poll();
        if (m == null) {
            break;
        }
        pipeline.fireChannelRead(m);
    } while (handle.continueReading());

    pipeline.fireChannelReadComplete();
}
 
Example 9
Source File: LocalChannel.java    From netty4.0.27Learn with Apache License 2.0 5 votes vote down vote up
private static void finishPeerRead(LocalChannel peer, ChannelPipeline peerPipeline) {
    if (peer.readInProgress) {
        peer.readInProgress = false;
        for (;;) {
            Object received = peer.inboundBuffer.poll();
            if (received == null) {
                break;
            }
            peerPipeline.fireChannelRead(received);
        }
        peerPipeline.fireChannelReadComplete();
    }
}
 
Example 10
Source File: LocalServerChannel.java    From netty4.0.27Learn with Apache License 2.0 5 votes vote down vote up
private void serve0(final LocalChannel child) {
    inboundBuffer.add(child);
    if (acceptInProgress) {
        acceptInProgress = false;
        ChannelPipeline pipeline = pipeline();
        for (;;) {
            Object m = inboundBuffer.poll();
            if (m == null) {
                break;
            }
            pipeline.fireChannelRead(m);
        }
        pipeline.fireChannelReadComplete();
    }
}
 
Example 11
Source File: EmbeddedChannel.java    From netty-4.1.22 with Apache License 2.0 5 votes vote down vote up
/**
 * Write messages to the inbound of this {@link Channel}.将消息写入该通道的入站。
 *
 * @param msgs the messages to be written
 *
 * @return {@code true} if the write operation did add something to the inbound buffer
 */
public boolean writeInbound(Object... msgs) {
    ensureOpen();
    if (msgs.length == 0) {
        return isNotEmpty(inboundMessages);
    }

    ChannelPipeline p = pipeline();
    for (Object m: msgs) {
        p.fireChannelRead(m);
    }

    flushInbound(false, voidPromise());
    return isNotEmpty(inboundMessages);
}
 
Example 12
Source File: LocalChannel.java    From netty4.0.27Learn with Apache License 2.0 5 votes vote down vote up
@Override
protected void doBeginRead() throws Exception {
    if (readInProgress) {
        return;
    }

    ChannelPipeline pipeline = pipeline();
    Queue<Object> inboundBuffer = this.inboundBuffer;
    if (inboundBuffer.isEmpty()) {
        readInProgress = true;
        return;
    }

    final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
    final Integer stackDepth = threadLocals.localChannelReaderStackDepth();
    if (stackDepth < MAX_READER_STACK_DEPTH) {
        threadLocals.setLocalChannelReaderStackDepth(stackDepth + 1);
        try {
            for (;;) {
                Object received = inboundBuffer.poll();
                if (received == null) {
                    break;
                }
                pipeline.fireChannelRead(received);
            }
            pipeline.fireChannelReadComplete();
        } finally {
            threadLocals.setLocalChannelReaderStackDepth(stackDepth);
        }
    } else {
        eventLoop().execute(readTask);
    }
}
 
Example 13
Source File: AbstractKQueueStreamChannel.java    From netty-4.1.22 with Apache License 2.0 4 votes vote down vote up
@Override
void readReady(final KQueueRecvByteAllocatorHandle allocHandle) {
    final ChannelConfig config = config();
    if (shouldBreakReadReady(config)) {
        clearReadFilter0();
        return;
    }
    final ChannelPipeline pipeline = pipeline();
    final ByteBufAllocator allocator = config.getAllocator();
    allocHandle.reset(config);
    readReadyBefore();

    ByteBuf byteBuf = null;
    boolean close = false;
    try {
        do {
            // we use a direct buffer here as the native implementations only be able
            // to handle direct buffers.
            byteBuf = allocHandle.allocate(allocator);
            allocHandle.lastBytesRead(doReadBytes(byteBuf));
            if (allocHandle.lastBytesRead() <= 0) {
                // nothing was read, release the buffer.
                byteBuf.release();
                byteBuf = null;
                close = allocHandle.lastBytesRead() < 0;
                if (close) {
                    // There is nothing left to read as we received an EOF.
                    readPending = false;
                }
                break;
            }
            allocHandle.incMessagesRead(1);
            readPending = false;
            pipeline.fireChannelRead(byteBuf);
            byteBuf = null;

            if (shouldBreakReadReady(config)) {
                // We need to do this for two reasons:
                //
                // - If the input was shutdown in between (which may be the case when the user did it in the
                //   fireChannelRead(...) method we should not try to read again to not produce any
                //   miss-leading exceptions.
                //
                // - If the user closes the channel we need to ensure we not try to read from it again as
                //   the filedescriptor may be re-used already by the OS if the system is handling a lot of
                //   concurrent connections and so needs a lot of filedescriptors. If not do this we risk
                //   reading data from a filedescriptor that belongs to another socket then the socket that
                //   was "wrapped" by this Channel implementation.
                break;
            }
        } while (allocHandle.continueReading());

        allocHandle.readComplete();
        pipeline.fireChannelReadComplete();

        if (close) {
            shutdownInput(false);
        }
    } catch (Throwable t) {
        handleReadException(pipeline, byteBuf, t, close, allocHandle);
    } finally {
        readReadyFinally(config);
    }
}
 
Example 14
Source File: AbstractNioByteChannel.java    From netty-4.1.22 with Apache License 2.0 4 votes vote down vote up
@Override
public final void read() {
    final ChannelConfig config = config();
    final ChannelPipeline pipeline = pipeline();
    final ByteBufAllocator allocator = config.getAllocator();
    final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
    allocHandle.reset(config);

    ByteBuf byteBuf = null;
    boolean close = false;
    try {
        do {
            byteBuf = allocHandle.allocate(allocator);
            allocHandle.lastBytesRead(doReadBytes(byteBuf));
            if (allocHandle.lastBytesRead() <= 0) {
                // nothing was read. release the buffer.
                byteBuf.release();
                byteBuf = null;
                close = allocHandle.lastBytesRead() < 0;
                if (close) {
                    // There is nothing left to read as we received an EOF.
                    readPending = false;
                }
                break;
            }

            allocHandle.incMessagesRead(1);
            readPending = false;
            pipeline.fireChannelRead(byteBuf);
            byteBuf = null;
        } while (allocHandle.continueReading());

        allocHandle.readComplete();
        pipeline.fireChannelReadComplete();

        if (close) {
            closeOnRead(pipeline);
        }
    } catch (Throwable t) {
        handleReadException(pipeline, byteBuf, t, close, allocHandle);
    } finally {
        // Check if there is a readPending which was not processed yet.
        // This could be for two reasons:
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
        //
        // See https://github.com/netty/netty/issues/2254
        if (!readPending && !config.isAutoRead()) {
            removeReadOp();
        }
    }
}
 
Example 15
Source File: AbstractOioMessageChannel.java    From netty-4.1.22 with Apache License 2.0 4 votes vote down vote up
@Override
protected void doRead() {
    if (!readPending) {
        // We have to check readPending here because the Runnable to read could have been scheduled and later
        // during the same read loop readPending was set to false.
        return;
    }
    // In OIO we should set readPending to false even if the read was not successful so we can schedule
    // another read on the event loop if no reads are done.
    readPending = false;

    final ChannelConfig config = config();
    final ChannelPipeline pipeline = pipeline();
    final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
    allocHandle.reset(config);

    boolean closed = false;
    Throwable exception = null;
    try {
        do {
            // Perform a read.
            int localRead = doReadMessages(readBuf);
            if (localRead == 0) {
                break;
            }
            if (localRead < 0) {
                closed = true;
                break;
            }

            allocHandle.incMessagesRead(localRead);
        } while (allocHandle.continueReading());
    } catch (Throwable t) {
        exception = t;
    }

    boolean readData = false;
    int size = readBuf.size();
    if (size > 0) {
        readData = true;
        for (int i = 0; i < size; i++) {
            readPending = false;
            pipeline.fireChannelRead(readBuf.get(i));
        }
        readBuf.clear();
        allocHandle.readComplete();
        pipeline.fireChannelReadComplete();
    }

    if (exception != null) {
        if (exception instanceof IOException) {
            closed = true;
        }

        pipeline.fireExceptionCaught(exception);
    }

    if (closed) {
        if (isOpen()) {
            unsafe().close(unsafe().voidPromise());
        }
    } else if (readPending || config.isAutoRead() || !readData && isActive()) {
        // Reading 0 bytes could mean there is a SocketTimeout and no data was actually read, so we
        // should execute read() again because no data may have been read.
        read();
    }
}
 
Example 16
Source File: AbstractOioByteChannel.java    From netty-4.1.22 with Apache License 2.0 4 votes vote down vote up
@Override
protected void doRead() {
    final ChannelConfig config = config();
    if (isInputShutdown() || !readPending) {
        // We have to check readPending here because the Runnable to read could have been scheduled and later
        // during the same read loop readPending was set to false.
        return;
    }
    // In OIO we should set readPending to false even if the read was not successful so we can schedule
    // another read on the event loop if no reads are done.
    readPending = false;

    final ChannelPipeline pipeline = pipeline();
    final ByteBufAllocator allocator = config.getAllocator();
    final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
    allocHandle.reset(config);

    ByteBuf byteBuf = null;
    boolean close = false;
    boolean readData = false;
    try {
        byteBuf = allocHandle.allocate(allocator);
        do {
            allocHandle.lastBytesRead(doReadBytes(byteBuf));
            if (allocHandle.lastBytesRead() <= 0) {
                if (!byteBuf.isReadable()) { // nothing was read. release the buffer.
                    byteBuf.release();
                    byteBuf = null;
                    close = allocHandle.lastBytesRead() < 0;
                    if (close) {
                        // There is nothing left to read as we received an EOF.
                        readPending = false;
                    }
                }
                break;
            } else {
                readData = true;
            }

            final int available = available();
            if (available <= 0) {
                break;
            }

            // Oio collects consecutive read operations into 1 ByteBuf before propagating up the pipeline.
            if (!byteBuf.isWritable()) {
                final int capacity = byteBuf.capacity();
                final int maxCapacity = byteBuf.maxCapacity();
                if (capacity == maxCapacity) {
                    allocHandle.incMessagesRead(1);
                    readPending = false;
                    pipeline.fireChannelRead(byteBuf);
                    byteBuf = allocHandle.allocate(allocator);
                } else {
                    final int writerIndex = byteBuf.writerIndex();
                    if (writerIndex + available > maxCapacity) {
                        byteBuf.capacity(maxCapacity);
                    } else {
                        byteBuf.ensureWritable(available);
                    }
                }
            }
        } while (allocHandle.continueReading());

        if (byteBuf != null) {
            // It is possible we allocated a buffer because the previous one was not writable, but then didn't use
            // it because allocHandle.continueReading() returned false.
            if (byteBuf.isReadable()) {
                readPending = false;
                pipeline.fireChannelRead(byteBuf);
            } else {
                byteBuf.release();
            }
            byteBuf = null;
        }

        if (readData) {
            allocHandle.readComplete();
            pipeline.fireChannelReadComplete();
        }

        if (close) {
            closeOnRead(pipeline);
        }
    } catch (Throwable t) {
        handleReadException(pipeline, byteBuf, t, close, allocHandle);
    } finally {
        if (readPending || config.isAutoRead() || !readData && isActive()) {
            // Reading 0 bytes could mean there is a SocketTimeout and no data was actually read, so we
            // should execute read() again because no data may have been read.
            read();
        }
    }
}
 
Example 17
Source File: EpollDomainSocketChannel.java    From netty-4.1.22 with Apache License 2.0 4 votes vote down vote up
private void epollInReadFd() {
    if (socket.isInputShutdown()) {
        clearEpollIn0();
        return;
    }
    final ChannelConfig config = config();
    final EpollRecvByteAllocatorHandle allocHandle = recvBufAllocHandle();
    allocHandle.edgeTriggered(isFlagSet(Native.EPOLLET));

    final ChannelPipeline pipeline = pipeline();
    allocHandle.reset(config);
    epollInBefore();

    try {
        readLoop: do {
            // lastBytesRead represents the fd. We use lastBytesRead because it must be set so that the
            // EpollRecvByteAllocatorHandle knows if it should try to read again or not when autoRead is
            // enabled.
            allocHandle.lastBytesRead(socket.recvFd());
            switch(allocHandle.lastBytesRead()) {
            case 0:
                break readLoop;
            case -1:
                close(voidPromise());
                return;
            default:
                allocHandle.incMessagesRead(1);
                readPending = false;
                pipeline.fireChannelRead(new FileDescriptor(allocHandle.lastBytesRead()));
                break;
            }
        } while (allocHandle.continueReading());

        allocHandle.readComplete();
        pipeline.fireChannelReadComplete();
    } catch (Throwable t) {
        allocHandle.readComplete();
        pipeline.fireChannelReadComplete();
        pipeline.fireExceptionCaught(t);
    } finally {
        epollInFinally(config);
    }
}
 
Example 18
Source File: AbstractNioByteChannel.java    From netty4.0.27Learn with Apache License 2.0 4 votes vote down vote up
@Override
public final void read() {
    final ChannelConfig config = config();
    if (!config.isAutoRead() && !isReadPending()) {
        // ChannelConfig.setAutoRead(false) was called in the meantime
        removeReadOp();
        return;
    }

    final ChannelPipeline pipeline = pipeline();
    final ByteBufAllocator allocator = config.getAllocator();
    final int maxMessagesPerRead = config.getMaxMessagesPerRead();
    RecvByteBufAllocator.Handle allocHandle = this.allocHandle;
    if (allocHandle == null) {
        this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle();
    }

    ByteBuf byteBuf = null;
    int messages = 0;
    boolean close = false;
    try {
        int totalReadAmount = 0;
        boolean readPendingReset = false;
        do {
            byteBuf = allocHandle.allocate(allocator);
            int writable = byteBuf.writableBytes();
            int localReadAmount = doReadBytes(byteBuf);
            if (localReadAmount <= 0) {
                // not was read release the buffer
                byteBuf.release();
                byteBuf = null;
                close = localReadAmount < 0;
                break;
            }
            if (!readPendingReset) {
                readPendingReset = true;
                setReadPending(false);
            }
            pipeline.fireChannelRead(byteBuf);
            byteBuf = null;

            if (totalReadAmount >= Integer.MAX_VALUE - localReadAmount) {
                // Avoid overflow.
                totalReadAmount = Integer.MAX_VALUE;
                break;
            }

            totalReadAmount += localReadAmount;

            // stop reading
            if (!config.isAutoRead()) {
                break;
            }

            if (localReadAmount < writable) {
                // Read less than what the buffer can hold,
                // which might mean we drained the recv buffer completely.
                break;
            }
        } while (++ messages < maxMessagesPerRead);

        pipeline.fireChannelReadComplete();
        allocHandle.record(totalReadAmount);

        if (close) {
            closeOnRead(pipeline);
            close = false;
        }
    } catch (Throwable t) {
        handleReadException(pipeline, byteBuf, t, close);
    } finally {
        // Check if there is a readPending which was not processed yet.
        // This could be for two reasons:
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
        //
        // See https://github.com/netty/netty/issues/2254
        if (!config.isAutoRead() && !isReadPending()) {
            removeReadOp();
        }
    }
}
 
Example 19
Source File: AbstractXnioSocketChannel.java    From netty-xnio-transport with Apache License 2.0 4 votes vote down vote up
@Override
public void handleEvent(ConduitStreamSourceChannel channel) {
    final ChannelConfig config = config();
    final ChannelPipeline pipeline = pipeline();
    final ByteBufAllocator allocator = config.getAllocator();
    final int maxMessagesPerRead = config.getMaxMessagesPerRead();
    RecvByteBufAllocator.Handle allocHandle = this.allocHandle;
    if (allocHandle == null) {
        this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle();
    }

    ByteBuf byteBuf = null;
    int messages = 0;
    boolean close = false;
    try {
        int byteBufCapacity = allocHandle.guess();
        int totalReadAmount = 0;
        do {
            byteBuf = allocator.ioBuffer(byteBufCapacity);
            int writable = byteBuf.writableBytes();
            int localReadAmount = byteBuf.writeBytes(channel, byteBuf.writableBytes());
            if (localReadAmount <= 0) {
                // not was read release the buffer
                byteBuf.release();
                close = localReadAmount < 0;
                break;
            }
            ((AbstractXnioUnsafe) unsafe()).readPending = false;
            pipeline.fireChannelRead(byteBuf);
            byteBuf = null;

            if (totalReadAmount >= Integer.MAX_VALUE - localReadAmount) {
                // Avoid overflow.
                totalReadAmount = Integer.MAX_VALUE;
                break;
            }

            totalReadAmount += localReadAmount;

            // stop reading
            if (!config.isAutoRead()) {
                break;
            }

            if (localReadAmount < writable) {
                // Read less than what the buffer can hold,
                // which might mean we drained the recv buffer completely.
                break;
            }
        } while (++ messages < maxMessagesPerRead);

        pipeline.fireChannelReadComplete();
        allocHandle.record(totalReadAmount);

        if (close) {
            closeOnRead();
            close = false;
        }
    } catch (Throwable t) {
        handleReadException(pipeline, byteBuf, t, close);
    } finally {
        // Check if there is a readPending which was not processed yet.
        // This could be for two reasons:
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
        // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
        //
        // See https://github.com/netty/netty/issues/2254
        if (!config.isAutoRead() && !((AbstractXnioUnsafe) unsafe()).readPending) {
            removeReadOp(channel);
        }
    }
}
 
Example 20
Source File: AbstractOioMessageChannel.java    From netty4.0.27Learn with Apache License 2.0 4 votes vote down vote up
@Override
protected void doRead() {
    final ChannelConfig config = config();
    final ChannelPipeline pipeline = pipeline();
    boolean closed = false;
    final int maxMessagesPerRead = config.getMaxMessagesPerRead();

    Throwable exception = null;
    int localRead = 0;
    int totalRead = 0;
    try {
        for (;;) {
            // Perform a read.
            localRead = doReadMessages(readBuf);
            if (localRead == 0) {
                break;
            }
            if (localRead < 0) {
                closed = true;
                break;
            }

            // Notify with the received messages and clear the buffer.
            int size = readBuf.size();
            for (int i = 0; i < size; i ++) {
                pipeline.fireChannelRead(readBuf.get(i));
            }
            readBuf.clear();

            // Do not read beyond maxMessagesPerRead.
            // Do not continue reading if autoRead has been turned off.
            totalRead += localRead;
            if (totalRead >= maxMessagesPerRead || !config.isAutoRead()) {
                break;
            }
        }
    } catch (Throwable t) {
        exception = t;
    }

    pipeline.fireChannelReadComplete();

    if (exception != null) {
        if (exception instanceof IOException) {
            closed = true;
        }

        pipeline().fireExceptionCaught(exception);
    }

    if (closed) {
        if (isOpen()) {
            unsafe().close(unsafe().voidPromise());
        }
    } else if (localRead == 0 && isActive()) {
        // If the read amount was 0 and the channel is still active we need to trigger a new read()
        // as otherwise we will never try to read again and the user will never know.
        // Just call read() is ok here as it will be submitted to the EventLoop as a task and so we are
        // able to process the rest of the tasks in the queue first.
        //
        // See https://github.com/netty/netty/issues/2404
        read();
    }
}