org.xnio.StreamConnection - java examples

Here are the examples of the java api org.xnio.StreamConnection taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

80 Examples 7

19 View Complete Implementation : JsrHybi07Handshake.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public WebSocketChannel createChannel(WebSocketHttpExchange exchange, final StreamConnection c, final ByteBufferPool buffers) {
    WebSocketChannel channel = super.createChannel(exchange, c, buffers);
    HandshakeUtil.setConfig(channel, config);
    return channel;
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
public boolean isActive() {
    StreamConnection conn = connection();
    return conn != null && conn.isOpen() && !closed;
}

19 View Complete Implementation : ConnectionUtils.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * Cleanly close a connection, by shutting down and flushing writes and then draining reads.
 * <p>
 * If this fails the connection is forcibly closed.
 *
 * @param connection The connection
 * @param additional Any additional resources to close once the connection has been closed
 */
public static void cleanClose(StreamConnection connection, Closeable... additional) {
    try {
        connection.getSinkChannel().shutdownWrites();
        if (!connection.getSinkChannel().flush()) {
            connection.getSinkChannel().setWriteListener(ChannelListeners.flushingChannelListener(new ChannelListener<ConduitStreamSinkChannel>() {

                @Override
                public void handleEvent(ConduitStreamSinkChannel channel) {
                    doDrain(connection, additional);
                }
            }, new ChannelExceptionHandler<ConduitStreamSinkChannel>() {

                @Override
                public void handleException(ConduitStreamSinkChannel channel, IOException exception) {
                    UndertowLogger.REQUEST_IO_LOGGER.ioException(exception);
                    IoUtils.safeClose(connection);
                    IoUtils.safeClose(additional);
                }
            }));
            connection.getSinkChannel().resumeWrites();
        } else {
            doDrain(connection, additional);
        }
    } catch (Throwable e) {
        if (e instanceof IOException) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException((IOException) e);
        } else {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(new IOException(e));
        }
        IoUtils.safeClose(connection);
        IoUtils.safeClose(additional);
    }
}

19 View Complete Implementation : NioTcpConnectionTestCase.java
Copyright Apache License 2.0
Author : xnio
@Override
protected void setWriteListener(StreamConnection channel, ChannelListener<ConduitStreamSinkChannel> writeListener) {
    channel.getSinkChannel().setWriteListener(writeListener);
}

19 View Complete Implementation : WrappingXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
/**
 * {@link AbstractXnioSocketChannel} implementation which allows you to wrap a pre-created XNIO channel.
 *
 * @author <a href="mailto:[email protected]">Norman Maurer</a>
 */
public final clreplaced WrappingXnioSocketChannel extends AbstractXnioSocketChannel implements IoThreadPowered {

    private final StreamConnection channel;

    private final XnioIoThread thread;

    WrappingXnioSocketChannel(AbstractXnioServerSocketChannel parent, StreamConnection channel) {
        super(parent);
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        this.channel = channel;
        this.thread = channel.getIoThread();
        config().setTcpNoDelay(true);
        channel.getSourceChannel().getReadSetter().set(new ReadListener());
    }

    /**
     * Create a new {@link WrappingXnioSocketChannel} which was created via the given {@link AcceptingChannel} and uses
     * the given {@link StreamConnection} under the covers.
     */
    public WrappingXnioSocketChannel(AcceptingChannel<StreamConnection> parent, StreamConnection channel) {
        this(new WrappingXnioServerSocketChannel(parent), channel);
        // register a EventLoop and start read
        unsafe().register(new XnioEventLoop(thread), unsafe().voidPromise());
        read();
    }

    /**
     * Create a {@link WrappingXnioSocketChannel} which uses the given {@link StreamConnection} under the covers.
     */
    public WrappingXnioSocketChannel(StreamConnection channel) {
        this((AbstractXnioServerSocketChannel) null, channel);
        // register a EventLoop and start read
        unsafe().register(new XnioEventLoop(thread), unsafe().voidPromise());
        read();
    }

    @Override
    public XnioIoThread ioThread() {
        return thread;
    }

    @Override
    protected XnioUnsafe newUnsafe() {
        return new XnioUnsafe();
    }

    @Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        throw new UnsupportedOperationException("Wrapped XNIO Channel");
    }

    private final clreplaced XnioUnsafe extends AbstractXnioUnsafe {

        @Override
        public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
            promise.setFailure(new UnsupportedOperationException("Wrapped XNIO Channel"));
        }
    }

    @Override
    protected <T> void setOption0(Option<T> option, T value) throws IOException {
        channel.setOption(option, value);
    }

    @Override
    protected <T> T getOption0(Option<T> option) throws IOException {
        return channel.getOption(option);
    }

    @Override
    protected StreamConnection connection() {
        return channel;
    }
}

19 View Complete Implementation : SslConduit.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * @author Stuart Douglas
 */
public clreplaced SslConduit implements StreamSourceConduit, StreamSinkConduit {

    public static final int MAX_READ_LISTENER_INVOCATIONS = Integer.getInteger("io.undertow.ssl.max-read-listener-invocations", 100);

    /**
     * If this is set we are in the middle of a handshake, and we cannot
     * read any more data until we have written out our wrap result
     */
    private static final int FLAG_READ_REQUIRES_WRITE = 1;

    /**
     * If this is set we are in the process of handshaking and we cannot write any
     * more data until we have read unwrapped data from the remote peer
     */
    private static final int FLAG_WRITE_REQUIRES_READ = 1 << 1;

    /**
     * If reads are resumed. The underlying delegate may not be resumed if a write is required
     * to make progress.
     */
    private static final int FLAG_READS_RESUMED = 1 << 2;

    /**
     * If writes are resumed, the underlying delegate may not be resumed if a read is required
     */
    private static final int FLAG_WRITES_RESUMED = 1 << 3;

    /**
     * If there is data in the {@link #dataToUnwrap} buffer, and the last unwrap attempt did not result
     * in a buffer underflow
     */
    private static final int FLAG_DATA_TO_UNWRAP = 1 << 4;

    /**
     * If the user has shutdown reads
     */
    private static final int FLAG_READ_SHUTDOWN = 1 << 5;

    /**
     * If the user has shutdown writes
     */
    private static final int FLAG_WRITE_SHUTDOWN = 1 << 6;

    /**
     * If the engine has been shut down
     */
    private static final int FLAG_ENGINE_INBOUND_SHUTDOWN = 1 << 7;

    /**
     * If the engine has been shut down
     */
    private static final int FLAG_ENGINE_OUTBOUND_SHUTDOWN = 1 << 8;

    private static final int FLAG_DELEGATE_SINK_SHUTDOWN = 1 << 9;

    private static final int FLAG_DELEGATE_SOURCE_SHUTDOWN = 1 << 10;

    private static final int FLAG_IN_HANDSHAKE = 1 << 11;

    private static final int FLAG_CLOSED = 1 << 12;

    private static final int FLAG_WRITE_CLOSED = 1 << 13;

    private static final int FLAG_READ_CLOSED = 1 << 14;

    public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);

    private final UndertowSslConnection connection;

    private final StreamConnection delegate;

    private SSLEngine engine;

    private final StreamSinkConduit sink;

    private final StreamSourceConduit source;

    private final ByteBufferPool bufferPool;

    private final Runnable handshakeCallback;

    private volatile int state = 0;

    private volatile int outstandingTasks = 0;

    /**
     * Data that has been wrapped and is ready to be sent to the underlying channel.
     *
     * This will be null if there is no data
     */
    private volatile PooledByteBuffer wrappedData;

    /**
     * Data that has been read from the underlying channel, and needs to be unwrapped.
     *
     * This will be null if there is no data. If there is data the {@link #FLAG_DATA_TO_UNWRAP}
     * flag must still be checked, otherwise there may be situations where even though some data
     * has been read there is not enough to unwrap (i.e. the engine returned buffer underflow).
     */
    private volatile PooledByteBuffer dataToUnwrap;

    /**
     * Unwrapped data, ready to be delivered to the application. Will be null if there is no data.
     *
     * If possible we avoid allocating this buffer, and instead unwrap directly into the end users buffer.
     */
    private volatile PooledByteBuffer unwrappedData;

    private SslWriteReadyHandler writeReadyHandler;

    private SslReadReadyHandler readReadyHandler;

    private int readListenerInvocationCount;

    private boolean invokingReadListenerHandshake = false;

    private final Runnable runReadListenerCommand = new Runnable() {

        @Override
        public void run() {
            final int count = readListenerInvocationCount;
            try {
                readReadyHandler.readReady();
            } finally {
                if (count == readListenerInvocationCount) {
                    readListenerInvocationCount = 0;
                }
            }
        }
    };

    private final Runnable runReadListenerAndResumeCommand = new Runnable() {

        @Override
        public void run() {
            if (allAreSet(state, FLAG_READS_RESUMED)) {
                delegate.getSourceChannel().resumeReads();
            }
            runReadListenerCommand.run();
        }
    };

    SslConduit(UndertowSslConnection connection, StreamConnection delegate, SSLEngine engine, ByteBufferPool bufferPool, Runnable handshakeCallback) {
        this.connection = connection;
        this.delegate = delegate;
        this.handshakeCallback = handshakeCallback;
        this.sink = delegate.getSinkChannel().getConduit();
        this.source = delegate.getSourceChannel().getConduit();
        this.engine = engine;
        this.bufferPool = bufferPool;
        delegate.getSourceChannel().getConduit().setReadReadyHandler(readReadyHandler = new SslReadReadyHandler(null));
        delegate.getSinkChannel().getConduit().setWriteReadyHandler(writeReadyHandler = new SslWriteReadyHandler(null));
        if (engine.getUseClientMode()) {
            state = FLAG_IN_HANDSHAKE | FLAG_READ_REQUIRES_WRITE;
        } else {
            state = FLAG_IN_HANDSHAKE | FLAG_WRITE_REQUIRES_READ;
        }
    }

    @Override
    public void terminateReads() throws IOException {
        state |= FLAG_READ_SHUTDOWN;
        notifyReadClosed();
    }

    @Override
    public boolean isReadShutdown() {
        return anyAreSet(state, FLAG_READ_SHUTDOWN);
    }

    @Override
    public void resumeReads() {
        if (anyAreSet(state, FLAG_READS_RESUMED)) {
            // already resumed
            return;
        }
        resumeReads(false);
    }

    @Override
    public void suspendReads() {
        state &= ~FLAG_READS_RESUMED;
        if (!allAreSet(state, FLAG_WRITES_RESUMED | FLAG_WRITE_REQUIRES_READ)) {
            delegate.getSourceChannel().suspendReads();
        }
    }

    @Override
    public void wakeupReads() {
        resumeReads(true);
    }

    private void resumeReads(boolean wakeup) {
        state |= FLAG_READS_RESUMED;
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            delegate.getSinkChannel().resumeWrites();
        } else {
            if (anyAreSet(state, FLAG_DATA_TO_UNWRAP) || wakeup || unwrappedData != null) {
                runReadListener(true);
            } else {
                delegate.getSourceChannel().resumeReads();
            }
        }
    }

    private void runReadListener(final boolean resumeInListener) {
        try {
            if (readListenerInvocationCount++ == MAX_READ_LISTENER_INVOCATIONS) {
                UndertowLogger.REQUEST_LOGGER.sslReadLoopDetected(this);
                IoUtils.safeClose(connection, delegate);
                close();
                return;
            }
            if (resumeInListener) {
                delegate.getIoThread().execute(runReadListenerAndResumeCommand);
            } else {
                delegate.getIoThread().execute(runReadListenerCommand);
            }
        } catch (Throwable e) {
            // will only happen on shutdown
            IoUtils.safeClose(connection, delegate);
            UndertowLogger.REQUEST_IO_LOGGER.debugf(e, "Failed to queue read listener invocation");
        }
    }

    private void runWriteListener() {
        try {
            delegate.getIoThread().execute(new Runnable() {

                @Override
                public void run() {
                    writeReadyHandler.writeReady();
                }
            });
        } catch (Throwable e) {
            // will only happen on shutdown
            IoUtils.safeClose(connection, delegate);
            UndertowLogger.REQUEST_IO_LOGGER.debugf(e, "Failed to queue read listener invocation");
        }
    }

    @Override
    public boolean isReadResumed() {
        return anyAreSet(state, FLAG_READS_RESUMED);
    }

    @Override
    public void awaitReadable() throws IOException {
        synchronized (this) {
            if (outstandingTasks > 0) {
                try {
                    wait();
                    return;
                } catch (InterruptedException e) {
                    throw new InterruptedIOException();
                }
            }
        }
        if (unwrappedData != null) {
            return;
        }
        if (anyAreSet(state, FLAG_DATA_TO_UNWRAP)) {
            return;
        }
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            awaitWritable();
            return;
        }
        source.awaitReadable();
    }

    @Override
    public void awaitReadable(long time, TimeUnit timeUnit) throws IOException {
        synchronized (this) {
            if (outstandingTasks > 0) {
                try {
                    wait(timeUnit.toMillis(time));
                    return;
                } catch (InterruptedException e) {
                    throw new InterruptedIOException();
                }
            }
        }
        if (unwrappedData != null) {
            return;
        }
        if (anyAreSet(state, FLAG_DATA_TO_UNWRAP)) {
            return;
        }
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            awaitWritable(time, timeUnit);
            return;
        }
        source.awaitReadable(time, timeUnit);
    }

    @Override
    public XnioIoThread getReadThread() {
        return delegate.getIoThread();
    }

    @Override
    public void setReadReadyHandler(ReadReadyHandler handler) {
        delegate.getSourceChannel().getConduit().setReadReadyHandler(readReadyHandler = new SslReadReadyHandler(handler));
    }

    @Override
    public long transferFrom(FileChannel src, long position, long count) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            throw new ClosedChannelException();
        }
        return src.transferTo(position, count, new ConduitWritableByteChannel(this));
    }

    @Override
    public long transferFrom(StreamSourceChannel source, long count, ByteBuffer throughBuffer) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            throw new ClosedChannelException();
        }
        return IoUtils.transfer(source, count, throughBuffer, new ConduitWritableByteChannel(this));
    }

    @Override
    public int write(ByteBuffer src) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            throw new ClosedChannelException();
        }
        return (int) doWrap(new ByteBuffer[] { src }, 0, 1);
    }

    @Override
    public long write(ByteBuffer[] srcs, int offs, int len) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            throw new ClosedChannelException();
        }
        return doWrap(srcs, offs, len);
    }

    @Override
    public int writeFinal(ByteBuffer src) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            throw new ClosedChannelException();
        }
        return Conduits.writeFinalBasic(this, src);
    }

    @Override
    public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
        return Conduits.writeFinalBasic(this, srcs, offset, length);
    }

    @Override
    public void terminateWrites() throws IOException {
        state |= FLAG_WRITE_SHUTDOWN;
    }

    @Override
    public boolean isWriteShutdown() {
        // todo
        return false;
    }

    @Override
    public void resumeWrites() {
        state |= FLAG_WRITES_RESUMED;
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            delegate.getSourceChannel().resumeReads();
        } else {
            delegate.getSinkChannel().resumeWrites();
        }
    }

    @Override
    public void suspendWrites() {
        state &= ~FLAG_WRITES_RESUMED;
        if (!allAreSet(state, FLAG_READS_RESUMED | FLAG_READ_REQUIRES_WRITE)) {
            delegate.getSinkChannel().suspendWrites();
        }
    }

    @Override
    public void wakeupWrites() {
        state |= FLAG_WRITES_RESUMED;
        getWriteThread().execute(new Runnable() {

            @Override
            public void run() {
                resumeWrites();
                writeReadyHandler.writeReady();
            }
        });
    }

    @Override
    public boolean isWriteResumed() {
        return anyAreSet(state, FLAG_WRITES_RESUMED);
    }

    @Override
    public void awaitWritable() throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            return;
        }
        if (outstandingTasks > 0) {
            synchronized (this) {
                if (outstandingTasks > 0) {
                    try {
                        this.wait();
                        return;
                    } catch (InterruptedException e) {
                        throw new InterruptedIOException();
                    }
                }
            }
        }
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            awaitReadable();
            return;
        }
        sink.awaitWritable();
    }

    @Override
    public void awaitWritable(long time, TimeUnit timeUnit) throws IOException {
        if (anyAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            return;
        }
        if (outstandingTasks > 0) {
            synchronized (this) {
                if (outstandingTasks > 0) {
                    try {
                        this.wait(timeUnit.toMillis(time));
                        return;
                    } catch (InterruptedException e) {
                        throw new InterruptedIOException();
                    }
                }
            }
        }
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            awaitReadable(time, timeUnit);
            return;
        }
        sink.awaitWritable();
    }

    @Override
    public XnioIoThread getWriteThread() {
        return delegate.getIoThread();
    }

    @Override
    public void setWriteReadyHandler(WriteReadyHandler handler) {
        delegate.getSinkChannel().getConduit().setWriteReadyHandler(writeReadyHandler = new SslWriteReadyHandler(handler));
    }

    @Override
    public void truncateWrites() throws IOException {
        try {
            notifyWriteClosed();
        } finally {
            delegate.getSinkChannel().close();
        }
    }

    @Override
    public boolean flush() throws IOException {
        if (anyAreSet(state, FLAG_DELEGATE_SINK_SHUTDOWN)) {
            return sink.flush();
        }
        if (wrappedData != null) {
            doWrap(null, 0, 0);
            if (wrappedData != null) {
                return false;
            }
        }
        if (allAreSet(state, FLAG_WRITE_SHUTDOWN)) {
            if (allAreClear(state, FLAG_ENGINE_OUTBOUND_SHUTDOWN)) {
                state |= FLAG_ENGINE_OUTBOUND_SHUTDOWN;
                engine.closeOutbound();
                doWrap(null, 0, 0);
                if (wrappedData != null) {
                    return false;
                }
            } else if (wrappedData != null && allAreClear(state, FLAG_DELEGATE_SINK_SHUTDOWN)) {
                doWrap(null, 0, 0);
                if (wrappedData != null) {
                    return false;
                }
            }
            if (allAreClear(state, FLAG_DELEGATE_SINK_SHUTDOWN)) {
                sink.terminateWrites();
                state |= FLAG_DELEGATE_SINK_SHUTDOWN;
                notifyWriteClosed();
            }
            boolean result = sink.flush();
            if (result && anyAreSet(state, FLAG_READ_CLOSED)) {
                closed();
            }
            return result;
        }
        return sink.flush();
    }

    @Override
    public long transferTo(long position, long count, FileChannel target) throws IOException {
        if (anyAreSet(state, FLAG_READ_SHUTDOWN)) {
            return -1;
        }
        return target.transferFrom(new ConduitReadableByteChannel(this), position, count);
    }

    @Override
    public long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException {
        if (anyAreSet(state, FLAG_READ_SHUTDOWN)) {
            return -1;
        }
        return IoUtils.transfer(new ConduitReadableByteChannel(this), count, throughBuffer, target);
    }

    @Override
    public int read(ByteBuffer dst) throws IOException {
        if (anyAreSet(state, FLAG_READ_SHUTDOWN)) {
            return -1;
        }
        return (int) doUnwrap(new ByteBuffer[] { dst }, 0, 1);
    }

    @Override
    public long read(ByteBuffer[] dsts, int offs, int len) throws IOException {
        if (anyAreSet(state, FLAG_READ_SHUTDOWN)) {
            return -1;
        }
        return doUnwrap(dsts, offs, len);
    }

    @Override
    public XnioWorker getWorker() {
        return delegate.getWorker();
    }

    void notifyWriteClosed() {
        if (anyAreSet(state, FLAG_WRITE_CLOSED)) {
            return;
        }
        boolean runListener = isWriteResumed() && anyAreSet(state, FLAG_CLOSED);
        connection.writeClosed();
        engine.closeOutbound();
        state |= FLAG_WRITE_CLOSED | FLAG_ENGINE_OUTBOUND_SHUTDOWN;
        if (anyAreSet(state, FLAG_READ_CLOSED)) {
            closed();
        }
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            notifyReadClosed();
        }
        state &= ~FLAG_WRITE_REQUIRES_READ;
        // unclean shutdown, run the listener
        if (runListener) {
            runWriteListener();
        }
    }

    void notifyReadClosed() {
        if (anyAreSet(state, FLAG_READ_CLOSED)) {
            return;
        }
        boolean runListener = isReadResumed() && anyAreSet(state, FLAG_CLOSED);
        connection.readClosed();
        try {
            engine.closeInbound();
        } catch (SSLException e) {
            UndertowLogger.REQUEST_IO_LOGGER.trace("Exception closing read side of SSL channel", e);
            if (allAreClear(state, FLAG_WRITE_CLOSED) && isWriteResumed()) {
                runWriteListener();
            }
        }
        state |= FLAG_READ_CLOSED | FLAG_ENGINE_INBOUND_SHUTDOWN | FLAG_READ_SHUTDOWN;
        if (anyAreSet(state, FLAG_WRITE_CLOSED)) {
            closed();
        }
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            notifyWriteClosed();
        }
        if (runListener) {
            runReadListener(false);
        }
    }

    public void startHandshake() throws SSLException {
        state |= FLAG_READ_REQUIRES_WRITE;
        engine.beginHandshake();
    }

    public SSLSession getSslSession() {
        return engine.getSession();
    }

    /**
     * Force the handshake to continue
     *
     * @throws IOException
     */
    private void doHandshake() throws IOException {
        doUnwrap(null, 0, 0);
        doWrap(null, 0, 0);
    }

    /**
     * Unwrap channel data into the user buffers. If no user buffer is supplied (e.g. during handshaking) then the
     * unwrap will happen into the channels unwrap buffer.
     *
     * If some data has already been unwrapped it will simply be copied into the user buffers
     * and no unwrap will actually take place.
     *
     * @return true if the unwrap operation made progress, false otherwise
     * @throws SSLException
     */
    private long doUnwrap(ByteBuffer[] userBuffers, int off, int len) throws IOException {
        if (anyAreSet(state, FLAG_CLOSED)) {
            throw new ClosedChannelException();
        }
        if (outstandingTasks > 0) {
            return 0;
        }
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            doWrap(null, 0, 0);
            if (allAreClear(state, FLAG_WRITE_REQUIRES_READ)) {
                // unless a wrap is immediately required we just return
                return 0;
            }
        }
        boolean bytesProduced = false;
        PooledByteBuffer unwrappedData = this.unwrappedData;
        // copy any exiting data
        if (unwrappedData != null) {
            if (userBuffers != null) {
                long copied = Buffers.copy(userBuffers, off, len, unwrappedData.getBuffer());
                if (!unwrappedData.getBuffer().hasRemaining()) {
                    unwrappedData.close();
                    this.unwrappedData = null;
                }
                if (copied > 0) {
                    readListenerInvocationCount = 0;
                }
                return copied;
            }
        }
        try {
            // we need to store how much data is in the unwrap buffer. If no progress can be made then we unset
            // the data to unwrap flag
            int dataToUnwrapLength;
            // try and read some data if we don't already have some
            if (allAreClear(state, FLAG_DATA_TO_UNWRAP)) {
                if (dataToUnwrap == null) {
                    dataToUnwrap = bufferPool.allocate();
                }
                int res;
                try {
                    res = source.read(dataToUnwrap.getBuffer());
                } catch (IOException | RuntimeException | Error e) {
                    dataToUnwrap.close();
                    dataToUnwrap = null;
                    throw e;
                }
                dataToUnwrap.getBuffer().flip();
                if (res == -1) {
                    dataToUnwrap.close();
                    dataToUnwrap = null;
                    notifyReadClosed();
                    return -1;
                } else if (res == 0 && engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
                    // its possible there was some data in the buffer from a previous unwrap that had a buffer underflow
                    // if not we just close the buffer so it does not hang around
                    if (!dataToUnwrap.getBuffer().hasRemaining()) {
                        dataToUnwrap.close();
                        dataToUnwrap = null;
                    }
                    return 0;
                }
            }
            dataToUnwrapLength = dataToUnwrap.getBuffer().remaining();
            long original = 0;
            if (userBuffers != null) {
                original = Buffers.remaining(userBuffers);
            }
            // perform the actual unwrap operation
            // if possible this is done into the the user buffers, however
            // if none are supplied or this results in a buffer overflow then we allocate our own
            SSLEngineResult result;
            boolean unwrapBufferUsed = false;
            try {
                if (userBuffers != null) {
                    result = engine.unwrap(this.dataToUnwrap.getBuffer(), userBuffers, off, len);
                    if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                        // not enough space in the user buffers
                        // we use our own
                        unwrappedData = bufferPool.allocate();
                        ByteBuffer[] d = new ByteBuffer[len + 1];
                        System.arraycopy(userBuffers, off, d, 0, len);
                        d[len] = unwrappedData.getBuffer();
                        result = engine.unwrap(this.dataToUnwrap.getBuffer(), d);
                        unwrapBufferUsed = true;
                    }
                    bytesProduced = result.bytesProduced() > 0;
                } else {
                    unwrapBufferUsed = true;
                    if (unwrappedData == null) {
                        unwrappedData = bufferPool.allocate();
                    } else {
                        unwrappedData.getBuffer().compact();
                    }
                    result = engine.unwrap(this.dataToUnwrap.getBuffer(), unwrappedData.getBuffer());
                    bytesProduced = result.bytesProduced() > 0;
                }
            } finally {
                if (unwrapBufferUsed) {
                    unwrappedData.getBuffer().flip();
                    if (!unwrappedData.getBuffer().hasRemaining()) {
                        unwrappedData.close();
                        unwrappedData = null;
                    }
                }
                this.unwrappedData = unwrappedData;
            }
            if (result.getStatus() == SSLEngineResult.Status.CLOSED) {
                if (dataToUnwrap != null) {
                    dataToUnwrap.close();
                    dataToUnwrap = null;
                }
                notifyReadClosed();
                return -1;
            }
            if (!handleHandshakeResult(result)) {
                if (this.dataToUnwrap.getBuffer().hasRemaining() && result.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW && dataToUnwrap.getBuffer().remaining() != dataToUnwrapLength) {
                    state |= FLAG_DATA_TO_UNWRAP;
                } else {
                    state &= ~FLAG_DATA_TO_UNWRAP;
                }
                return 0;
            }
            if (result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                state &= ~FLAG_DATA_TO_UNWRAP;
            } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                UndertowLogger.REQUEST_LOGGER.sslBufferOverflow(this);
                IoUtils.safeClose(delegate);
            } else if (this.dataToUnwrap.getBuffer().hasRemaining() && dataToUnwrap.getBuffer().remaining() != dataToUnwrapLength) {
                state |= FLAG_DATA_TO_UNWRAP;
            } else {
                state &= ~FLAG_DATA_TO_UNWRAP;
            }
            if (userBuffers == null) {
                return 0;
            } else {
                long res = original - Buffers.remaining(userBuffers);
                if (res > 0) {
                    // if data has been successfully returned this is not a read loop
                    readListenerInvocationCount = 0;
                }
                return res;
            }
        } catch (SSLException e) {
            try {
                try {
                    // we make an effort to write out the final record
                    // this is best effort, there are no guarantees
                    clearWriteRequiresRead();
                    doWrap(null, 0, 0);
                    flush();
                } catch (Exception e2) {
                    UndertowLogger.REQUEST_LOGGER.debug("Failed to write out final SSL record", e2);
                }
                close();
            } catch (Throwable ex) {
                // we ignore this
                UndertowLogger.REQUEST_LOGGER.debug("Exception closing SSLConduit after exception in doUnwrap", ex);
            }
            throw e;
        } catch (RuntimeException | IOException | Error e) {
            try {
                close();
            } catch (Throwable ex) {
                // we ignore this
                UndertowLogger.REQUEST_LOGGER.debug("Exception closing SSLConduit after exception in doUnwrap", ex);
            }
            throw e;
        } finally {
            // if there is data in the buffer and reads are resumed we should re-run the listener
            boolean requiresListenerInvocation = false;
            // we always need to re-invoke if bytes have been produced, as the engine may have buffered some data
            if (bytesProduced || (unwrappedData != null && unwrappedData.isOpen() && unwrappedData.getBuffer().hasRemaining())) {
                requiresListenerInvocation = true;
            }
            if (dataToUnwrap != null) {
                // if there is no data in the buffer we just free it
                if (!dataToUnwrap.getBuffer().hasRemaining()) {
                    dataToUnwrap.close();
                    dataToUnwrap = null;
                    state &= ~FLAG_DATA_TO_UNWRAP;
                } else if (allAreClear(state, FLAG_DATA_TO_UNWRAP)) {
                    // if there is not enough data in the buffer we compact it to make room for more
                    dataToUnwrap.getBuffer().compact();
                } else {
                    // there is more data, make sure we trigger a read listener invocation
                    requiresListenerInvocation = true;
                }
            }
            // if we are in the read listener handshake we don't need to invoke
            // as it is about to be invoked anyway
            if (requiresListenerInvocation && (anyAreSet(state, FLAG_READS_RESUMED) || allAreSet(state, FLAG_WRITE_REQUIRES_READ | FLAG_WRITES_RESUMED)) && !invokingReadListenerHandshake) {
                runReadListener(false);
            }
        }
    }

    /**
     * Wraps the user data and attempts to send it to the remote client. If data has already been buffered then
     * this is attempted to be sent first.
     *
     * If the supplied buffers are null then a wrap operation is still attempted, which will happen during the
     * handshaking process.
     * @param userBuffers The buffers
     * @param off         The offset
     * @param len         The length
     * @return The amount of data consumed
     * @throws IOException
     */
    private long doWrap(ByteBuffer[] userBuffers, int off, int len) throws IOException {
        if (anyAreSet(state, FLAG_CLOSED)) {
            throw new ClosedChannelException();
        }
        if (outstandingTasks > 0) {
            return 0;
        }
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            doUnwrap(null, 0, 0);
            if (allAreClear(state, FLAG_READ_REQUIRES_WRITE)) {
                // unless a wrap is immediatly required we just return
                return 0;
            }
        }
        if (wrappedData != null) {
            int res = sink.write(wrappedData.getBuffer());
            if (res == 0 || wrappedData.getBuffer().hasRemaining()) {
                return 0;
            }
            wrappedData.getBuffer().clear();
        } else {
            wrappedData = bufferPool.allocate();
        }
        try {
            SSLEngineResult result = null;
            while (result == null || (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP && result.getStatus() != SSLEngineResult.Status.BUFFER_OVERFLOW)) {
                if (userBuffers == null) {
                    result = engine.wrap(EMPTY_BUFFER, wrappedData.getBuffer());
                } else {
                    result = engine.wrap(userBuffers, off, len, wrappedData.getBuffer());
                }
            }
            wrappedData.getBuffer().flip();
            if (result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                // todo: can this happen?
                throw new IOException("underflow");
            } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                if (!wrappedData.getBuffer().hasRemaining()) {
                    // if an earlier wrap suceeded we ignore this
                    // todo: handle properly
                    throw new IOException("overflow");
                }
            }
            // attempt to write it out, if we fail we just return
            // we ignore the handshake status, as wrap will get called again
            if (wrappedData.getBuffer().hasRemaining()) {
                sink.write(wrappedData.getBuffer());
            }
            // if it was not a complete write we just return
            if (wrappedData.getBuffer().hasRemaining()) {
                return result.bytesConsumed();
            }
            if (!handleHandshakeResult(result)) {
                return 0;
            }
            if (result.getStatus() == SSLEngineResult.Status.CLOSED && userBuffers != null) {
                notifyWriteClosed();
                throw new ClosedChannelException();
            }
            return result.bytesConsumed();
        } catch (RuntimeException | IOException | Error e) {
            try {
                close();
            } catch (Throwable ex) {
                UndertowLogger.REQUEST_LOGGER.debug("Exception closing SSLConduit after exception in doWrap()", ex);
            }
            throw e;
        } finally {
            // this can be cleared if the channel is fully closed
            if (wrappedData != null) {
                if (!wrappedData.getBuffer().hasRemaining()) {
                    wrappedData.close();
                    wrappedData = null;
                }
            }
        }
    }

    private boolean handleHandshakeResult(SSLEngineResult result) throws IOException {
        switch(result.getHandshakeStatus()) {
            case NEED_TASK:
                {
                    state |= FLAG_IN_HANDSHAKE;
                    clearReadRequiresWrite();
                    clearWriteRequiresRead();
                    runTasks();
                    return false;
                }
            case NEED_UNWRAP:
                {
                    clearReadRequiresWrite();
                    state |= FLAG_WRITE_REQUIRES_READ | FLAG_IN_HANDSHAKE;
                    sink.suspendWrites();
                    if (anyAreSet(state, FLAG_WRITES_RESUMED)) {
                        source.resumeReads();
                    }
                    return false;
                }
            case NEED_WRAP:
                {
                    clearWriteRequiresRead();
                    state |= FLAG_READ_REQUIRES_WRITE | FLAG_IN_HANDSHAKE;
                    source.suspendReads();
                    if (anyAreSet(state, FLAG_READS_RESUMED)) {
                        sink.resumeWrites();
                    }
                    return false;
                }
            case FINISHED:
                {
                    if (anyAreSet(state, FLAG_IN_HANDSHAKE)) {
                        state &= ~FLAG_IN_HANDSHAKE;
                        handshakeCallback.run();
                    }
                }
        }
        clearReadRequiresWrite();
        clearWriteRequiresRead();
        return true;
    }

    private void clearReadRequiresWrite() {
        if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
            state &= ~FLAG_READ_REQUIRES_WRITE;
            if (anyAreSet(state, FLAG_READS_RESUMED)) {
                resumeReads(false);
            }
            if (allAreClear(state, FLAG_WRITES_RESUMED)) {
                sink.suspendWrites();
            }
        }
    }

    private void clearWriteRequiresRead() {
        if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ)) {
            state &= ~FLAG_WRITE_REQUIRES_READ;
            if (anyAreSet(state, FLAG_WRITES_RESUMED)) {
                wakeupWrites();
            }
            if (allAreClear(state, FLAG_READS_RESUMED)) {
                source.suspendReads();
            }
        }
    }

    private void closed() {
        if (anyAreSet(state, FLAG_CLOSED)) {
            return;
        }
        state |= FLAG_CLOSED | FLAG_DELEGATE_SINK_SHUTDOWN | FLAG_DELEGATE_SOURCE_SHUTDOWN | FLAG_WRITE_SHUTDOWN | FLAG_READ_SHUTDOWN;
        notifyReadClosed();
        notifyWriteClosed();
        if (dataToUnwrap != null) {
            dataToUnwrap.close();
            dataToUnwrap = null;
        }
        if (unwrappedData != null) {
            unwrappedData.close();
            unwrappedData = null;
        }
        if (wrappedData != null) {
            wrappedData.close();
            wrappedData = null;
        }
        if (allAreClear(state, FLAG_ENGINE_OUTBOUND_SHUTDOWN)) {
            engine.closeOutbound();
        }
        if (allAreClear(state, FLAG_ENGINE_INBOUND_SHUTDOWN)) {
            try {
                engine.closeInbound();
            } catch (SSLException e) {
                UndertowLogger.REQUEST_LOGGER.ioException(e);
            } catch (Throwable t) {
                UndertowLogger.REQUEST_LOGGER.handleUnexpectedFailure(t);
            }
        }
        IoUtils.safeClose(delegate);
    }

    /**
     * Execute all the tasks in the worker
     *
     * Once they are complete we notify any waiting threads and wakeup reads/writes as appropriate
     */
    private void runTasks() {
        // don't run anything in the IO thread till the tasks are done
        delegate.getSinkChannel().suspendWrites();
        delegate.getSourceChannel().suspendReads();
        List<Runnable> tasks = new ArrayList<>();
        Runnable t = engine.getDelegatedTask();
        while (t != null) {
            tasks.add(t);
            t = engine.getDelegatedTask();
        }
        synchronized (this) {
            outstandingTasks += tasks.size();
            for (final Runnable task : tasks) {
                getWorker().execute(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            task.run();
                        } finally {
                            synchronized (SslConduit.this) {
                                if (outstandingTasks == 1) {
                                    getWriteThread().execute(new Runnable() {

                                        @Override
                                        public void run() {
                                            synchronized (SslConduit.this) {
                                                SslConduit.this.notifyAll();
                                                --outstandingTasks;
                                                try {
                                                    doHandshake();
                                                } catch (IOException | RuntimeException | Error e) {
                                                    UndertowLogger.REQUEST_LOGGER.error("Closing SSLConduit after exception on handshake", e);
                                                    IoUtils.safeClose(connection);
                                                }
                                                if (anyAreSet(state, FLAG_READS_RESUMED)) {
                                                    // wakeup, because we need to run an unwrap even if there is no data to be read
                                                    wakeupReads();
                                                }
                                                if (anyAreSet(state, FLAG_WRITES_RESUMED)) {
                                                    // we don't need to wakeup, as the channel should be writable
                                                    resumeWrites();
                                                }
                                            }
                                        }
                                    });
                                } else {
                                    outstandingTasks--;
                                }
                            }
                        }
                    }
                });
            }
        }
    }

    public SSLEngine getSSLEngine() {
        return engine;
    }

    /**
     * forcibly closes the connection
     */
    public void close() {
        closed();
    }

    /**
     * Read ready handler that deals with read-requires-write semantics
     */
    private clreplaced SslReadReadyHandler implements ReadReadyHandler {

        private final ReadReadyHandler delegateHandler;

        private SslReadReadyHandler(ReadReadyHandler delegateHandler) {
            this.delegateHandler = delegateHandler;
        }

        @Override
        public void readReady() {
            if (anyAreSet(state, FLAG_WRITE_REQUIRES_READ) && anyAreSet(state, FLAG_WRITES_RESUMED | FLAG_READS_RESUMED) && !anyAreSet(state, FLAG_ENGINE_INBOUND_SHUTDOWN)) {
                try {
                    invokingReadListenerHandshake = true;
                    doHandshake();
                } catch (IOException e) {
                    UndertowLogger.REQUEST_LOGGER.ioException(e);
                    IoUtils.safeClose(delegate);
                } catch (Throwable t) {
                    UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t);
                    IoUtils.safeClose(delegate);
                } finally {
                    invokingReadListenerHandshake = false;
                }
                if (!anyAreSet(state, FLAG_READS_RESUMED) && !allAreSet(state, FLAG_WRITE_REQUIRES_READ | FLAG_WRITES_RESUMED)) {
                    delegate.getSourceChannel().suspendReads();
                }
            }
            boolean noProgress = false;
            int initialDataToUnwrap = -1;
            int initialUnwrapped = -1;
            if (anyAreSet(state, FLAG_READS_RESUMED)) {
                if (delegateHandler == null) {
                    final ChannelListener<? super ConduitStreamSourceChannel> readListener = connection.getSourceChannel().getReadListener();
                    if (readListener == null) {
                        suspendReads();
                    } else {
                        if (anyAreSet(state, FLAG_DATA_TO_UNWRAP)) {
                            initialDataToUnwrap = dataToUnwrap.getBuffer().remaining();
                        }
                        if (unwrappedData != null) {
                            initialUnwrapped = unwrappedData.getBuffer().remaining();
                        }
                        ChannelListeners.invokeChannelListener(connection.getSourceChannel(), readListener);
                        if (anyAreSet(state, FLAG_DATA_TO_UNWRAP) && initialDataToUnwrap == dataToUnwrap.getBuffer().remaining()) {
                            noProgress = true;
                        } else if (unwrappedData != null && unwrappedData.getBuffer().remaining() == initialUnwrapped) {
                            noProgress = true;
                        }
                    }
                } else {
                    delegateHandler.readReady();
                }
            }
            if (anyAreSet(state, FLAG_READS_RESUMED) && (unwrappedData != null || anyAreSet(state, FLAG_DATA_TO_UNWRAP))) {
                if (anyAreSet(state, FLAG_READ_CLOSED)) {
                    if (unwrappedData != null) {
                        unwrappedData.close();
                    }
                    if (dataToUnwrap != null) {
                        dataToUnwrap.close();
                    }
                    unwrappedData = null;
                    dataToUnwrap = null;
                } else {
                    // there is data in the buffers so we do a wakeup
                    // as we may not get an actual read notification
                    // if we need to write for the SSL engine to progress we don't invoke the read listener
                    // otherwise it will run in a busy loop till the channel becomes writable
                    // we also don't re-run if we have outstanding tasks
                    if (!(anyAreSet(state, FLAG_READ_REQUIRES_WRITE) && wrappedData != null) && outstandingTasks == 0 && !noProgress) {
                        runReadListener(false);
                    }
                }
            }
        }

        @Override
        public void forceTermination() {
            try {
                if (delegateHandler != null) {
                    delegateHandler.forceTermination();
                }
            } finally {
                IoUtils.safeClose(delegate);
            }
        }

        @Override
        public void terminated() {
            ChannelListeners.invokeChannelListener(connection.getSourceChannel(), connection.getSourceChannel().getCloseListener());
        }
    }

    /**
     * write read handler that deals with write-requires-read semantics
     */
    private clreplaced SslWriteReadyHandler implements WriteReadyHandler {

        private final WriteReadyHandler delegateHandler;

        private SslWriteReadyHandler(WriteReadyHandler delegateHandler) {
            this.delegateHandler = delegateHandler;
        }

        @Override
        public void forceTermination() {
            try {
                if (delegateHandler != null) {
                    delegateHandler.forceTermination();
                }
            } finally {
                IoUtils.safeClose(delegate);
            }
        }

        @Override
        public void terminated() {
            ChannelListeners.invokeChannelListener(connection.getSinkChannel(), connection.getSinkChannel().getCloseListener());
        }

        @Override
        public void writeReady() {
            if (anyAreSet(state, FLAG_READ_REQUIRES_WRITE)) {
                if (anyAreSet(state, FLAG_READS_RESUMED)) {
                    readReadyHandler.readReady();
                } else {
                    try {
                        doHandshake();
                    } catch (IOException e) {
                        UndertowLogger.REQUEST_LOGGER.ioException(e);
                        IoUtils.safeClose(delegate);
                    } catch (Throwable t) {
                        UndertowLogger.REQUEST_LOGGER.handleUnexpectedFailure(t);
                        IoUtils.safeClose(delegate);
                    }
                }
            }
            if (anyAreSet(state, FLAG_WRITES_RESUMED)) {
                if (delegateHandler == null) {
                    final ChannelListener<? super ConduitStreamSinkChannel> writeListener = connection.getSinkChannel().getWriteListener();
                    if (writeListener == null) {
                        suspendWrites();
                    } else {
                        ChannelListeners.invokeChannelListener(connection.getSinkChannel(), writeListener);
                    }
                } else {
                    delegateHandler.writeReady();
                }
            }
            if (!anyAreSet(state, FLAG_WRITES_RESUMED | FLAG_READ_REQUIRES_WRITE)) {
                delegate.getSinkChannel().suspendWrites();
            }
        }
    }

    public void setSslEngine(SSLEngine engine) {
        this.engine = engine;
    }

    @Override
    public String toString() {
        return "SslConduit{" + "state=" + state + ", outstandingTasks=" + outstandingTasks + ", wrappedData=" + wrappedData + ", dataToUnwrap=" + dataToUnwrap + ", unwrappedData=" + unwrappedData + '}';
    }
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
public boolean isInputShutdown() {
    StreamConnection conn = connection();
    return conn == null || conn.isReadShutdown();
}

19 View Complete Implementation : UndertowSslConnection.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * @author Stuart Douglas
 */
clreplaced UndertowSslConnection extends SslConnection {

    private static final Set<Option<?>> SUPPORTED_OPTIONS = Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create();

    private final StreamConnection delegate;

    private final SslConduit sslConduit;

    private final ChannelListener.SimpleSetter<SslConnection> handshakeSetter = new ChannelListener.SimpleSetter<>();

    private final SSLEngine engine;

    /**
     * Construct a new instance.
     *
     * @param delegate the underlying connection
     */
    UndertowSslConnection(StreamConnection delegate, SSLEngine engine, ByteBufferPool bufferPool) {
        super(delegate.getIoThread());
        this.delegate = delegate;
        this.engine = engine;
        sslConduit = new SslConduit(this, delegate, engine, bufferPool, new HandshakeCallback());
        setSourceConduit(sslConduit);
        setSinkConduit(sslConduit);
    }

    @Override
    public void startHandshake() throws IOException {
        sslConduit.startHandshake();
    }

    @Override
    public SSLSession getSslSession() {
        return sslConduit.getSslSession();
    }

    @Override
    public ChannelListener.Setter<? extends SslConnection> getHandshakeSetter() {
        return handshakeSetter;
    }

    @Override
    protected void notifyWriteClosed() {
        sslConduit.notifyWriteClosed();
    }

    @Override
    protected void notifyReadClosed() {
        sslConduit.notifyReadClosed();
    }

    @Override
    public SocketAddress getPeerAddress() {
        return delegate.getPeerAddress();
    }

    @Override
    public SocketAddress getLocalAddress() {
        return delegate.getLocalAddress();
    }

    public SSLEngine getSSLEngine() {
        return sslConduit.getSSLEngine();
    }

    SslConduit getSslConduit() {
        return sslConduit;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            try {
                return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
            } finally {
                engine.setNeedClientAuth(value == SslClientAuthMode.REQUIRED);
                engine.setWantClientAuth(value == SslClientAuthMode.REQUESTED);
            }
        } else if (option == Options.SECURE) {
            throw new IllegalArgumentException();
        } else {
            return delegate.setOption(option, value);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getOption(final Option<T> option) throws IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
        } else {
            return option == Options.SECURE ? (T) Boolean.TRUE : delegate.getOption(option);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supportsOption(final Option<?> option) {
        return SUPPORTED_OPTIONS.contains(option) || delegate.supportsOption(option);
    }

    @Override
    protected boolean readClosed() {
        return super.readClosed();
    }

    @Override
    protected boolean writeClosed() {
        return super.writeClosed();
    }

    protected void closeAction() {
        sslConduit.close();
    }

    private final clreplaced HandshakeCallback implements Runnable {

        @Override
        public void run() {
            final ChannelListener<? super SslConnection> listener = handshakeSetter.get();
            if (listener == null) {
                return;
            }
            ChannelListeners.<SslConnection>invokeChannelListener(UndertowSslConnection.this, listener);
        }
    }
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
protected void doClose() throws Exception {
    closed = true;
    StreamConnection conn = connection();
    if (conn != null) {
        suspend(conn);
        conn.close();
    }
}

19 View Complete Implementation : Hybi07Handshake.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public WebSocketChannel createChannel(WebSocketHttpExchange exchange, final StreamConnection channel, final ByteBufferPool pool) {
    List<ExtensionFunction> extensionFunctions = initExtensions(exchange);
    return new WebSocket07Channel(channel, pool, getWebSocketLocation(exchange), exchange.getResponseHeader(Headers.SEC_WEB_SOCKET_PROTOCOL_STRING), false, !extensionFunctions.isEmpty(), CompositeExtensionFunction.compose(extensionFunctions), exchange.getPeerConnections(), exchange.getOptions());
}

19 View Complete Implementation : NioTcpConnectionTestCase.java
Copyright Apache License 2.0
Author : xnio
@Override
protected void resumeReads(StreamConnection channel) {
    channel.getSourceChannel().resumeReads();
}

19 View Complete Implementation : JsseAcceptingSslStreamConnection.java
Copyright Apache License 2.0
Author : xnio
@Override
public SslConnection accept(StreamConnection tcpConnection, SSLEngine engine) throws IOException {
    if (!JsseXnioSsl.NEW_IMPL) {
        return new JsseSslStreamConnection(tcpConnection, engine, socketBufferPool, applicationBufferPool, startTls);
    }
    JsseSslConnection connection = new JsseSslConnection(tcpConnection, engine, socketBufferPool, applicationBufferPool);
    if (!startTls) {
        try {
            connection.startHandshake();
        } catch (IOException e) {
            IoUtils.safeClose(connection);
            throw e;
        }
    }
    return connection;
}

19 View Complete Implementation : ServletUpgradeListener.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public void handleUpgrade(final StreamConnection channel, final HttpServerExchange exchange) {
    channel.getCloseSetter().set(new ChannelListener<StreamConnection>() {

        @Override
        public void handleEvent(StreamConnection channel) {
            try {
                destroyAction.call(null, null);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    });
    this.exchange.getConnection().getWorker().execute(new Runnable() {

        @Override
        public void run() {
            try {
                initAction.call(exchange, channel);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    });
}

19 View Complete Implementation : TcpConnectionTestCase.java
Copyright Apache License 2.0
Author : xnio
/**
 * Tests a pair of connected TCP connections (client/server).
 *
 * @author <a href="mailto:[email protected]">Flavia Rainone</a>
 */
public clreplaced TcpConnectionTestCase extends AbstractStreamSinkSourceChannelTest<StreamSinkChannel, StreamSourceChannel> {

    protected SocketAddress bindAddress;

    protected StreamConnection connection = null;

    protected StreamConnection serverConnection = null;

    protected AcceptingChannel<? extends StreamConnection> server;

    @Before
    public void createServer() throws IOException {
        bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 12345);
        final ChannelListener<AcceptingChannel<StreamConnection>> acceptingChannelListener = new TestChannelListener<AcceptingChannel<StreamConnection>>();
        ;
        server = worker.createStreamConnectionServer(bindAddress, acceptingChannelListener, OptionMap.EMPTY);
        replacedertNotNull(server);
    }

    @After
    public void closeServer() throws IOException {
        if (server != null) {
            server.close();
        }
    }

    @Override
    protected synchronized void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener<StreamSinkChannel> channelListener, TestChannelListener<StreamSourceChannel> serverChannelListener) throws IOException {
        if (connection != null) {
            connection.close();
            serverConnection.close();
        }
        final IoFuture<StreamConnection> openedConnection = xnioWorker.openStreamConnection(bindAddress, null, optionMap);
        final FutureResult<StreamConnection> accepted = new FutureResult<StreamConnection>(xnioWorker);
        server.getAcceptSetter().set(new ChannelListener<AcceptingChannel<? extends StreamConnection>>() {

            public void handleEvent(final AcceptingChannel<? extends StreamConnection> channel) {
                try {
                    accepted.setResult(server.accept());
                } catch (IOException e) {
                    accepted.setException(e);
                }
            }
        });
        server.resumeAccepts();
        serverConnection = accepted.getIoFuture().get();
        connection = openedConnection.get();
        replacedertNotNull(serverConnection);
        replacedertNotNull(connection);
        channelListener.handleEvent(connection.getSinkChannel());
        serverChannelListener.handleEvent(serverConnection.getSourceChannel());
    }

    @Test
    @Ignore("unreliable")
    public void optionSetup() throws IOException {
        initChannels();
        final Option<?>[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.CLOSE_ABORT, Options.IP_TRAFFIC_CLreplaced, Options.KEEP_ALIVE, Options.READ_TIMEOUT, Options.RECEIVE_BUFFER, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.TCP_NODELAY, Options.TCP_OOB_INLINE, Options.WRITE_TIMEOUT);
        for (Option<?> option : unsupportedOptions) {
            replacedertFalse("Channel supports " + option, connection.supportsOption(option));
            replacedertNull("Expected null value for option " + option + " but got " + connection.getOption(option) + " instead", connection.getOption(option));
        }
        replacedertTrue(connection.supportsOption(Options.CLOSE_ABORT));
        replacedertFalse(connection.getOption(Options.CLOSE_ABORT));
        replacedertTrue(connection.supportsOption(Options.IP_TRAFFIC_CLreplaced));
        replacedertEquals(0, (int) connection.getOption(Options.IP_TRAFFIC_CLreplaced));
        replacedertTrue(connection.supportsOption(Options.KEEP_ALIVE));
        replacedertFalse(connection.getOption(Options.KEEP_ALIVE));
        replacedertTrue(connection.supportsOption(Options.READ_TIMEOUT));
        replacedertEquals(0, (int) connection.getOption(Options.READ_TIMEOUT));
        replacedertTrue(connection.supportsOption(Options.RECEIVE_BUFFER));
        replacedertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0);
        replacedertTrue(connection.supportsOption(Options.SEND_BUFFER));
        replacedertTrue(connection.getOption(Options.SEND_BUFFER) > 0);
        replacedertTrue(connection.supportsOption(Options.TCP_NODELAY));
        replacedertNotNull(connection.getOption(Options.TCP_NODELAY));
        replacedertTrue(connection.supportsOption(Options.TCP_OOB_INLINE));
        replacedertFalse(connection.getOption(Options.TCP_OOB_INLINE));
        replacedertTrue(connection.supportsOption(Options.WRITE_TIMEOUT));
        replacedertEquals(0, (int) connection.getOption(Options.WRITE_TIMEOUT));
        connection.setOption(Options.CLOSE_ABORT, true);
        connection.setOption(Options.IP_TRAFFIC_CLreplaced, 5);
        connection.setOption(Options.KEEP_ALIVE, true);
        connection.setOption(Options.READ_TIMEOUT, 234095747);
        connection.setOption(Options.RECEIVE_BUFFER, 5000);
        connection.setOption(Options.SEND_BUFFER, 3000);
        connection.setOption(Options.TCP_NODELAY, true);
        connection.setOption(Options.TCP_OOB_INLINE, true);
        connection.setOption(Options.WRITE_TIMEOUT, 1301093);
        // unsupported
        replacedertNull("Unexpected option value: " + connection.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), connection.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 50000));
        replacedertTrue(connection.getOption(Options.CLOSE_ABORT));
        // it is okay that 5 is not returned
        replacedertTrue(connection.getOption(Options.IP_TRAFFIC_CLreplaced) >= 0);
        // 5 value will only be set if the channels' family equals StandardProtocolFamily.INET
        replacedertTrue(connection.getOption(Options.KEEP_ALIVE));
        replacedertEquals(234095747, (int) connection.getOption(Options.READ_TIMEOUT));
        replacedertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0);
        replacedertTrue(connection.getOption(Options.SEND_BUFFER) >= 3000);
        replacedertTrue(connection.getOption(Options.TCP_NODELAY));
        replacedertTrue(connection.getOption(Options.TCP_OOB_INLINE));
        replacedertEquals(1301093, (int) connection.getOption(Options.WRITE_TIMEOUT));
        replacedertTrue(connection.getOption(Options.CLOSE_ABORT));
        // unsupported
        replacedertNull(connection.getOption(Options.MAX_INBOUND_MESSAGE_SIZE));
        replacedertTrue(connection.setOption(Options.CLOSE_ABORT, false));
        replacedertTrue(connection.setOption(Options.IP_TRAFFIC_CLreplaced, 30) >= 0);
        replacedertTrue(connection.setOption(Options.KEEP_ALIVE, false));
        replacedertEquals(234095747, (int) connection.setOption(Options.READ_TIMEOUT, 1290455));
        replacedertTrue(connection.setOption(Options.RECEIVE_BUFFER, 3000) >= 5000);
        replacedertTrue(connection.setOption(Options.SEND_BUFFER, 5000) >= 3000);
        replacedertTrue(connection.setOption(Options.TCP_NODELAY, false));
        replacedertTrue(connection.setOption(Options.TCP_OOB_INLINE, false));
        replacedertEquals(1301093, (int) connection.setOption(Options.WRITE_TIMEOUT, 293265));
        replacedertFalse(connection.getOption(Options.CLOSE_ABORT));
        replacedertTrue(connection.getOption(Options.IP_TRAFFIC_CLreplaced) >= 0);
        replacedertFalse(connection.getOption(Options.KEEP_ALIVE));
        replacedertEquals(1290455, (int) connection.getOption(Options.READ_TIMEOUT));
        replacedertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0);
        replacedertEquals(5000, (int) connection.getOption(Options.SEND_BUFFER));
        replacedertFalse(connection.getOption(Options.TCP_NODELAY));
        replacedertFalse(connection.getOption(Options.TCP_OOB_INLINE));
        replacedertEquals(293265, (int) connection.getOption(Options.WRITE_TIMEOUT));
        replacedertFalse(connection.setOption(Options.CLOSE_ABORT, null));
        replacedertFalse(connection.setOption(Options.KEEP_ALIVE, null));
        replacedertEquals(1290455, (int) connection.setOption(Options.READ_TIMEOUT, null));
        replacedertFalse(connection.setOption(Options.TCP_NODELAY, null));
        replacedertFalse(connection.setOption(Options.TCP_OOB_INLINE, null));
        replacedertEquals(293265, (int) connection.setOption(Options.WRITE_TIMEOUT, null));
        replacedertFalse(connection.getOption(Options.CLOSE_ABORT));
        replacedertTrue((int) connection.getOption(Options.IP_TRAFFIC_CLreplaced) >= 0);
        replacedertFalse(connection.getOption(Options.KEEP_ALIVE));
        replacedertEquals(0, (int) connection.getOption(Options.READ_TIMEOUT));
        replacedertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0);
        replacedertTrue(connection.getOption(Options.SEND_BUFFER) > 0);
        replacedertNotNull(connection.getOption(Options.TCP_NODELAY));
        replacedertFalse(connection.getOption(Options.TCP_OOB_INLINE));
        replacedertEquals(0, (int) connection.getOption(Options.WRITE_TIMEOUT));
    }

    @Test
    public void channelAddress() throws IOException {
        initChannels();
        replacedertEquals(bindAddress, connection.getPeerAddress());
        replacedertEquals(bindAddress, connection.getPeerAddress(InetSocketAddress.clreplaced));
        replacedertNull(connection.getPeerAddress(LocalSocketAddress.clreplaced));
        final SocketAddress clientAddress = connection.getLocalAddress();
        replacedertNotNull(clientAddress);
        replacedertEquals(clientAddress, connection.getLocalAddress((InetSocketAddress.clreplaced)));
        replacedertNull(connection.getLocalAddress((LocalSocketAddress.clreplaced)));
        replacedertNotNull(connection.toString());
    }
}

19 View Complete Implementation : ReadTimeoutStreamSourceConduit.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * Wrapper for read timeout. This should always be the first wrapper applied to the underlying channel.
 *
 * @author Stuart Douglas
 * @see org.xnio.Options#READ_TIMEOUT
 */
public final clreplaced ReadTimeoutStreamSourceConduit extends AbstractStreamSourceConduit<StreamSourceConduit> {

    private XnioExecutor.Key handle;

    private final StreamConnection connection;

    private volatile long expireTime = -1;

    private final OpenListener openListener;

    // we add 50ms to the timeout to make sure the underlying channel has actually timed out
    private static final int FUZZ_FACTOR = 50;

    private final Runnable timeoutCommand = new Runnable() {

        @Override
        public void run() {
            handle = null;
            if (expireTime == -1) {
                return;
            }
            long current = System.currentTimeMillis();
            if (current < expireTime) {
                // timeout has been bumped, re-schedule
                handle = WorkerUtils.executeAfter(connection.getIoThread(), timeoutCommand, (expireTime - current) + FUZZ_FACTOR, TimeUnit.MILLISECONDS);
                return;
            }
            UndertowLogger.REQUEST_LOGGER.tracef("Timing out channel %s due to inactivity", connection.getSourceChannel());
            IoUtils.safeClose(connection);
            if (connection.getSourceChannel().isReadResumed()) {
                ChannelListeners.invokeChannelListener(connection.getSourceChannel(), connection.getSourceChannel().getReadListener());
            }
            if (connection.getSinkChannel().isWriteResumed()) {
                ChannelListeners.invokeChannelListener(connection.getSinkChannel(), connection.getSinkChannel().getWriteListener());
            }
        }
    };

    public ReadTimeoutStreamSourceConduit(final StreamSourceConduit delegate, StreamConnection connection, OpenListener openListener) {
        super(delegate);
        this.connection = connection;
        this.openListener = openListener;
        final ReadReadyHandler handler = new ReadReadyHandler.ChannelListenerHandler<>(connection.getSourceChannel());
        delegate.setReadReadyHandler(new ReadReadyHandler() {

            @Override
            public void readReady() {
                handler.readReady();
            }

            @Override
            public void forceTermination() {
                cleanup();
                handler.forceTermination();
            }

            @Override
            public void terminated() {
                cleanup();
                handler.terminated();
            }
        });
    }

    private void handleReadTimeout(final long ret) throws IOException {
        if (!connection.isOpen()) {
            cleanup();
            return;
        }
        if (ret == -1) {
            cleanup();
            return;
        }
        if (ret == 0 && handle != null) {
            return;
        }
        Integer timeout = getTimeout();
        if (timeout == null || timeout <= 0) {
            return;
        }
        long currentTime = System.currentTimeMillis();
        long expireTimeVar = expireTime;
        if (expireTimeVar != -1 && currentTime > expireTimeVar) {
            IoUtils.safeClose(connection);
            throw new ClosedChannelException();
        }
        expireTime = currentTime + timeout;
    }

    @Override
    public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
        long ret = super.transferTo(position, count, target);
        handleReadTimeout(ret);
        return ret;
    }

    @Override
    public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
        long ret = super.transferTo(count, throughBuffer, target);
        handleReadTimeout(ret);
        return ret;
    }

    @Override
    public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException {
        long ret = super.read(dsts, offset, length);
        handleReadTimeout(ret);
        return ret;
    }

    @Override
    public int read(final ByteBuffer dst) throws IOException {
        int ret = super.read(dst);
        handleReadTimeout(ret);
        return ret;
    }

    @Override
    public void awaitReadable() throws IOException {
        Integer timeout = getTimeout();
        if (timeout != null && timeout > 0) {
            super.awaitReadable(timeout + FUZZ_FACTOR, TimeUnit.MILLISECONDS);
        } else {
            super.awaitReadable();
        }
    }

    @Override
    public void awaitReadable(long time, TimeUnit timeUnit) throws IOException {
        Integer timeout = getTimeout();
        if (timeout != null && timeout > 0) {
            long millis = timeUnit.toMillis(time);
            super.awaitReadable(Math.min(millis, timeout + FUZZ_FACTOR), TimeUnit.MILLISECONDS);
        } else {
            super.awaitReadable(time, timeUnit);
        }
    }

    private Integer getTimeout() {
        Integer timeout = 0;
        try {
            timeout = connection.getSourceChannel().getOption(Options.READ_TIMEOUT);
        } catch (IOException ignore) {
        // should never happen
        }
        Integer idleTimeout = openListener.getUndertowOptions().get(UndertowOptions.IDLE_TIMEOUT);
        if ((timeout == null || timeout <= 0) && idleTimeout != null) {
            timeout = idleTimeout;
        } else if (timeout != null && idleTimeout != null && idleTimeout > 0) {
            timeout = Math.min(timeout, idleTimeout);
        }
        return timeout;
    }

    @Override
    public void terminateReads() throws IOException {
        super.terminateReads();
        cleanup();
    }

    private void cleanup() {
        if (handle != null) {
            handle.remove();
            handle = null;
        }
    }

    @Override
    public void resumeReads() {
        super.resumeReads();
        handleResumeTimeout();
    }

    @Override
    public void suspendReads() {
        super.suspendReads();
        XnioExecutor.Key handle = this.handle;
        if (handle != null) {
            handle.remove();
            this.handle = null;
        }
    }

    @Override
    public void wakeupReads() {
        super.wakeupReads();
        handleResumeTimeout();
    }

    private void handleResumeTimeout() {
        Integer timeout = getTimeout();
        if (timeout == null || timeout <= 0) {
            return;
        }
        long currentTime = System.currentTimeMillis();
        expireTime = currentTime + timeout;
        XnioExecutor.Key key = handle;
        if (key == null) {
            handle = connection.getIoThread().executeAfter(timeoutCommand, timeout, TimeUnit.MILLISECONDS);
        }
    }
}

19 View Complete Implementation : AbstractXnioServerSocketChannel.java
Copyright Apache License 2.0
Author : xnio
private static StreamConnection[] connectionsArray(int size) {
    StreamConnection[] array = connections.get();
    if (array == null || array.length < size) {
        array = new StreamConnection[size];
        connections.set(array);
    }
    return array;
}

19 View Complete Implementation : ProxyProtocolOpenListener.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public void handleEvent(StreamConnection streamConnection) {
    streamConnection.getSourceChannel().setReadListener(new ProxyProtocolReadListener(streamConnection, openListener, ssl, bufferPool, sslOptionMap));
    streamConnection.getSourceChannel().wakeupReads();
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
public boolean isOpen() {
    StreamConnection conn = connection();
    return (conn == null || conn.isOpen()) && !closed;
}

19 View Complete Implementation : AbstractServerConnection.java
Copyright Apache License 2.0
Author : undertow-io
public abstract clreplaced AbstractServerConnection extends ServerConnection {

    protected final StreamConnection channel;

    protected final CloseSetter closeSetter;

    protected final ByteBufferPool bufferPool;

    protected final HttpHandler rootHandler;

    protected final OptionMap undertowOptions;

    protected final StreamSourceConduit originalSourceConduit;

    protected final StreamSinkConduit originalSinkConduit;

    protected final List<CloseListener> closeListeners = new LinkedList<>();

    protected HttpServerExchange current;

    private final int bufferSize;

    private XnioBufferPoolAdaptor poolAdaptor;

    /**
     * Any extra bytes that were read from the channel. This could be data for this requests, or the next response.
     */
    protected PooledByteBuffer extraBytes;

    public AbstractServerConnection(StreamConnection channel, final ByteBufferPool bufferPool, final HttpHandler rootHandler, final OptionMap undertowOptions, final int bufferSize) {
        this.channel = channel;
        this.bufferPool = bufferPool;
        this.rootHandler = rootHandler;
        this.undertowOptions = undertowOptions;
        this.bufferSize = bufferSize;
        closeSetter = new CloseSetter();
        if (channel != null) {
            this.originalSinkConduit = channel.getSinkChannel().getConduit();
            this.originalSourceConduit = channel.getSourceChannel().getConduit();
            channel.setCloseListener(closeSetter);
        } else {
            this.originalSinkConduit = null;
            this.originalSourceConduit = null;
        }
    }

    @Override
    public Pool<ByteBuffer> getBufferPool() {
        if (poolAdaptor == null) {
            poolAdaptor = new XnioBufferPoolAdaptor(getByteBufferPool());
        }
        return poolAdaptor;
    }

    /**
     * Get the root HTTP handler for this connection.
     *
     * @return the root HTTP handler for this connection
     */
    public HttpHandler getRootHandler() {
        return rootHandler;
    }

    /**
     * Get the buffer pool for this connection.
     *
     * @return the buffer pool for this connection
     */
    @Override
    public ByteBufferPool getByteBufferPool() {
        return bufferPool;
    }

    /**
     * Get the underlying channel.
     *
     * @return the underlying channel
     */
    public StreamConnection getChannel() {
        return channel;
    }

    @Override
    public ChannelListener.Setter<ServerConnection> getCloseSetter() {
        return closeSetter;
    }

    @Override
    public XnioWorker getWorker() {
        return channel.getWorker();
    }

    @Override
    public XnioIoThread getIoThread() {
        if (channel == null) {
            return null;
        }
        return channel.getIoThread();
    }

    @Override
    public boolean isOpen() {
        return channel.isOpen();
    }

    @Override
    public boolean supportsOption(final Option<?> option) {
        return channel.supportsOption(option);
    }

    @Override
    public <T> T getOption(final Option<T> option) throws IOException {
        return channel.getOption(option);
    }

    @Override
    public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
        return channel.setOption(option, value);
    }

    @Override
    public void close() throws IOException {
        channel.close();
    }

    @Override
    public SocketAddress getPeerAddress() {
        return channel.getPeerAddress();
    }

    @Override
    public <A extends SocketAddress> A getPeerAddress(final Clreplaced<A> type) {
        return channel.getPeerAddress(type);
    }

    @Override
    public SocketAddress getLocalAddress() {
        return channel.getLocalAddress();
    }

    @Override
    public <A extends SocketAddress> A getLocalAddress(final Clreplaced<A> type) {
        return channel.getLocalAddress(type);
    }

    @Override
    public OptionMap getUndertowOptions() {
        return undertowOptions;
    }

    /**
     * @return The size of the buffers allocated by the buffer pool
     */
    @Override
    public int getBufferSize() {
        return bufferSize;
    }

    public PooledByteBuffer getExtraBytes() {
        if (extraBytes != null && !extraBytes.getBuffer().hasRemaining()) {
            extraBytes.close();
            extraBytes = null;
            return null;
        }
        return extraBytes;
    }

    public void setExtraBytes(final PooledByteBuffer extraBytes) {
        this.extraBytes = extraBytes;
    }

    /**
     * @return The original source conduit
     */
    public StreamSourceConduit getOriginalSourceConduit() {
        return originalSourceConduit;
    }

    /**
     * @return The original underlying sink conduit
     */
    public StreamSinkConduit getOriginalSinkConduit() {
        return originalSinkConduit;
    }

    /**
     * Resets the channel to its original state, effectively disabling all current conduit
     * wrappers. The current state is encapsulated inside a {@link ConduitState} object that
     * can be used the restore the channel.
     *
     * @return An opaque representation of the previous channel state
     */
    public ConduitState resetChannel() {
        ConduitState ret = new ConduitState(channel.getSinkChannel().getConduit(), channel.getSourceChannel().getConduit());
        channel.getSinkChannel().setConduit(originalSinkConduit);
        channel.getSourceChannel().setConduit(originalSourceConduit);
        return ret;
    }

    /**
     * Resets the channel to its original state, effectively disabling all current conduit
     * wrappers. The current state is lost.
     */
    public void clearChannel() {
        channel.getSinkChannel().setConduit(originalSinkConduit);
        channel.getSourceChannel().setConduit(originalSourceConduit);
    }

    /**
     * Restores the channel conduits to a previous state.
     *
     * @param state The original state
     * @see #resetChannel()
     */
    public void restoreChannel(final ConduitState state) {
        channel.getSinkChannel().setConduit(state.sink);
        channel.getSourceChannel().setConduit(state.source);
    }

    public static clreplaced ConduitState {

        final StreamSinkConduit sink;

        final StreamSourceConduit source;

        private ConduitState(final StreamSinkConduit sink, final StreamSourceConduit source) {
            this.sink = sink;
            this.source = source;
        }
    }

    protected static StreamSinkConduit sink(ConduitState state) {
        return state.sink;
    }

    protected static StreamSourceConduit source(ConduitState state) {
        return state.source;
    }

    @Override
    public void addCloseListener(CloseListener listener) {
        this.closeListeners.add(listener);
    }

    @Override
    protected ConduitStreamSinkChannel getSinkChannel() {
        return channel.getSinkChannel();
    }

    @Override
    protected ConduitStreamSourceChannel getSourceChannel() {
        return channel.getSourceChannel();
    }

    protected void setUpgradeListener(HttpUpgradeListener upgradeListener) {
        throw UndertowMessages.MESSAGES.upgradeNotSupported();
    }

    @Override
    protected void maxEnreplacedySizeUpdated(HttpServerExchange exchange) {
    }

    private clreplaced CloseSetter implements ChannelListener.Setter<ServerConnection>, ChannelListener<StreamConnection> {

        private ChannelListener<? super ServerConnection> listener;

        @Override
        public void set(ChannelListener<? super ServerConnection> listener) {
            this.listener = listener;
        }

        @Override
        public void handleEvent(StreamConnection channel) {
            try {
                for (CloseListener l : closeListeners) {
                    try {
                        l.closed(AbstractServerConnection.this);
                    } catch (Throwable e) {
                        UndertowLogger.REQUEST_LOGGER.exceptionInvokingCloseListener(l, e);
                    }
                }
                if (current != null) {
                    current.endExchange();
                }
                ChannelListeners.invokeChannelListener(AbstractServerConnection.this, listener);
            } finally {
                if (extraBytes != null) {
                    extraBytes.close();
                    extraBytes = null;
                }
            }
        }
    }
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
protected SocketAddress remoteAddress0() {
    StreamConnection conn = connection();
    if (conn == null) {
        return null;
    }
    return conn.getPeerAddress();
}

19 View Complete Implementation : ConnectionUtils.java
Copyright Apache License 2.0
Author : undertow-io
private static void doDrain(final StreamConnection connection, final Closeable... additional) {
    if (!connection.getSourceChannel().isOpen()) {
        IoUtils.safeClose(connection);
        IoUtils.safeClose(additional);
        return;
    }
    final ByteBuffer b = ByteBuffer.allocate(1);
    try {
        int res = connection.getSourceChannel().read(b);
        b.clear();
        if (res == 0) {
            final XnioExecutor.Key key = WorkerUtils.executeAfter(connection.getIoThread(), new Runnable() {

                @Override
                public void run() {
                    IoUtils.safeClose(connection);
                    IoUtils.safeClose(additional);
                }
            }, MAX_DRAIN_TIME, TimeUnit.MILLISECONDS);
            connection.getSourceChannel().setReadListener(new ChannelListener<ConduitStreamSourceChannel>() {

                @Override
                public void handleEvent(ConduitStreamSourceChannel channel) {
                    try {
                        int res = channel.read(b);
                        if (res != 0) {
                            IoUtils.safeClose(connection);
                            IoUtils.safeClose(additional);
                            key.remove();
                        }
                    } catch (Exception e) {
                        if (e instanceof IOException) {
                            UndertowLogger.REQUEST_IO_LOGGER.ioException((IOException) e);
                        } else {
                            UndertowLogger.REQUEST_IO_LOGGER.ioException(new IOException(e));
                        }
                        IoUtils.safeClose(connection);
                        IoUtils.safeClose(additional);
                        key.remove();
                    }
                }
            });
            connection.getSourceChannel().resumeReads();
        } else {
            IoUtils.safeClose(connection);
            IoUtils.safeClose(additional);
        }
    } catch (Throwable e) {
        if (e instanceof IOException) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException((IOException) e);
        } else {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(new IOException(e));
        }
        IoUtils.safeClose(connection);
        IoUtils.safeClose(additional);
    }
}

19 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
public boolean isOutputShutdown() {
    StreamConnection conn = connection();
    return conn == null || conn.isWriteShutdown();
}

19 View Complete Implementation : HttpClientConnection.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * @author <a href="mailto:[email protected]">David M. Lloyd</a>
 */
clreplaced HttpClientConnection extends AbstractAttachable implements Closeable, ClientConnection {

    public final ConduitListener<StreamSinkConduit> requestFinishListener = new ConduitListener<StreamSinkConduit>() {

        @Override
        public void handleEvent(StreamSinkConduit channel) {
            if (currentRequest != null) {
                currentRequest.terminateRequest();
            }
        }
    };

    public final ConduitListener<StreamSourceConduit> responseFinishedListener = new ConduitListener<StreamSourceConduit>() {

        @Override
        public void handleEvent(StreamSourceConduit channel) {
            if (currentRequest != null) {
                currentRequest.terminateResponse();
            }
        }
    };

    private static final Logger log = Logger.getLogger(HttpClientConnection.clreplaced);

    private final Deque<HttpClientExchange> pendingQueue = new ArrayDeque<>();

    private HttpClientExchange currentRequest;

    private HttpResponseBuilder pendingResponse;

    private final OptionMap options;

    private final StreamConnection connection;

    private final PushBackStreamSourceConduit pushBackStreamSourceConduit;

    private final ClientReadListener clientReadListener = new ClientReadListener();

    private final ByteBufferPool bufferPool;

    private PooledByteBuffer pooledBuffer;

    private final StreamSinkConduit originalSinkConduit;

    private static final int UPGRADED = 1 << 28;

    private static final int UPGRADE_REQUESTED = 1 << 29;

    private static final int CLOSE_REQ = 1 << 30;

    private static final int CLOSED = 1 << 31;

    private int state;

    private final ChannelListener.SimpleSetter<HttpClientConnection> closeSetter = new ChannelListener.SimpleSetter<>();

    private final ClientStatistics clientStatistics;

    private int requestCount;

    private int read, written;

    private boolean http2Tried = false;

    private boolean http2UpgradeReceived = false;

    /**
     * The actual connection if this has been upgraded to h2c
     */
    private ClientConnection http2Delegate;

    private final List<ChannelListener<ClientConnection>> closeListeners = new CopyOnWriteArrayList<>();

    HttpClientConnection(final StreamConnection connection, final OptionMap options, final ByteBufferPool bufferPool) {
        // first we set up statistics, if required
        if (options.get(UndertowOptions.ENABLE_STATISTICS, false)) {
            clientStatistics = new ClientStatisticsImpl();
            connection.getSinkChannel().setConduit(new BytesSentStreamSinkConduit(connection.getSinkChannel().getConduit(), new ByteActivityCallback() {

                @Override
                public void activity(long bytes) {
                    written += bytes;
                }
            }));
            connection.getSourceChannel().setConduit(new BytesReceivedStreamSourceConduit(connection.getSourceChannel().getConduit(), new ByteActivityCallback() {

                @Override
                public void activity(long bytes) {
                    read += bytes;
                }
            }));
        } else {
            clientStatistics = null;
        }
        this.options = options;
        this.connection = connection;
        this.pushBackStreamSourceConduit = new PushBackStreamSourceConduit(connection.getSourceChannel().getConduit());
        this.connection.getSourceChannel().setConduit(pushBackStreamSourceConduit);
        this.bufferPool = bufferPool;
        this.originalSinkConduit = connection.getSinkChannel().getConduit();
        connection.getCloseSetter().set(new ChannelListener<StreamConnection>() {

            public void handleEvent(StreamConnection channel) {
                log.debugf("connection to %s closed", getPeerAddress());
                HttpClientConnection.this.state |= CLOSED;
                ChannelListeners.invokeChannelListener(HttpClientConnection.this, closeSetter.get());
                try {
                    if (pooledBuffer != null) {
                        pooledBuffer.close();
                    }
                } catch (Throwable ignored) {
                }
                for (ChannelListener<ClientConnection> listener : closeListeners) {
                    listener.handleEvent(HttpClientConnection.this);
                }
                HttpClientExchange pending = pendingQueue.poll();
                while (pending != null) {
                    pending.setFailed(new ClosedChannelException());
                    pending = pendingQueue.poll();
                }
                if (currentRequest != null) {
                    currentRequest.setFailed(new ClosedChannelException());
                    currentRequest = null;
                    pendingResponse = null;
                }
            }
        });
        // we resume reads, so if the target goes away we get notified
        connection.getSourceChannel().setReadListener(clientReadListener);
        connection.getSourceChannel().resumeReads();
    }

    @Override
    public ByteBufferPool getBufferPool() {
        return bufferPool;
    }

    @Override
    public SocketAddress getPeerAddress() {
        return connection.getPeerAddress();
    }

    StreamConnection getConnection() {
        return connection;
    }

    @Override
    public <A extends SocketAddress> A getPeerAddress(Clreplaced<A> type) {
        return connection.getPeerAddress(type);
    }

    @Override
    public ChannelListener.Setter<? extends HttpClientConnection> getCloseSetter() {
        return closeSetter;
    }

    @Override
    public SocketAddress getLocalAddress() {
        return connection.getLocalAddress();
    }

    @Override
    public <A extends SocketAddress> A getLocalAddress(Clreplaced<A> type) {
        return connection.getLocalAddress(type);
    }

    @Override
    public XnioWorker getWorker() {
        return connection.getWorker();
    }

    @Override
    public XnioIoThread getIoThread() {
        return connection.getIoThread();
    }

    @Override
    public boolean isOpen() {
        if (http2Delegate != null) {
            return http2Delegate.isOpen();
        }
        return connection.isOpen() && allAreClear(state, CLOSE_REQ | CLOSED);
    }

    @Override
    public boolean supportsOption(Option<?> option) {
        if (http2Delegate != null) {
            return http2Delegate.supportsOption(option);
        }
        return connection.supportsOption(option);
    }

    @Override
    public <T> T getOption(Option<T> option) throws IOException {
        if (http2Delegate != null) {
            return http2Delegate.getOption(option);
        }
        return connection.getOption(option);
    }

    @Override
    public <T> T setOption(Option<T> option, T value) throws IllegalArgumentException, IOException {
        if (http2Delegate != null) {
            return http2Delegate.setOption(option, value);
        }
        return connection.setOption(option, value);
    }

    @Override
    public boolean isUpgraded() {
        if (http2Delegate != null) {
            return http2Delegate.isUpgraded();
        }
        return anyAreSet(state, UPGRADE_REQUESTED | UPGRADED);
    }

    @Override
    public boolean isPushSupported() {
        if (http2Delegate != null) {
            return http2Delegate.isPushSupported();
        }
        return false;
    }

    @Override
    public boolean isMultiplexingSupported() {
        if (http2Delegate != null) {
            return http2Delegate.isMultiplexingSupported();
        }
        return false;
    }

    @Override
    public ClientStatistics getStatistics() {
        if (http2Delegate != null) {
            return http2Delegate.getStatistics();
        }
        return clientStatistics;
    }

    @Override
    public boolean isUpgradeSupported() {
        if (http2Delegate != null) {
            return false;
        }
        return true;
    }

    @Override
    public void addCloseListener(ChannelListener<ClientConnection> listener) {
        closeListeners.add(listener);
    }

    @Override
    public void sendRequest(final ClientRequest request, final ClientCallback<ClientExchange> clientCallback) {
        if (http2Delegate != null) {
            http2Delegate.sendRequest(request, clientCallback);
            return;
        }
        if (anyAreSet(state, UPGRADE_REQUESTED | UPGRADED | CLOSE_REQ | CLOSED)) {
            clientCallback.failed(UndertowClientMessages.MESSAGES.invalidConnectionState());
            return;
        }
        final HttpClientExchange httpClientExchange = new HttpClientExchange(clientCallback, request, this);
        boolean ssl = this.connection instanceof SslConnection;
        if (!ssl && !http2Tried && options.get(UndertowOptions.ENABLE_HTTP2, false) && !request.getRequestHeaders().contains(Headers.UPGRADE)) {
            // this is the first request, as we want to try a HTTP2 upgrade
            request.getRequestHeaders().put(new HttpString("HTTP2-Settings"), Http2ClearClientProvider.createSettingsFrame(options, bufferPool));
            request.getRequestHeaders().put(Headers.UPGRADE, Http2Channel.CLEARTEXT_UPGRADE_STRING);
            request.getRequestHeaders().put(Headers.CONNECTION, "Upgrade, HTTP2-Settings");
            http2Tried = true;
        }
        if (currentRequest == null) {
            initiateRequest(httpClientExchange);
        } else {
            pendingQueue.add(httpClientExchange);
        }
    }

    private void initiateRequest(HttpClientExchange httpClientExchange) {
        this.requestCount++;
        currentRequest = httpClientExchange;
        pendingResponse = new HttpResponseBuilder();
        ClientRequest request = httpClientExchange.getRequest();
        String connectionString = request.getRequestHeaders().getFirst(Headers.CONNECTION);
        if (connectionString != null) {
            if (Headers.CLOSE.equalToString(connectionString)) {
                state |= CLOSE_REQ;
            } else if (Headers.UPGRADE.equalToString(connectionString)) {
                state |= UPGRADE_REQUESTED;
            }
        } else if (request.getProtocol() != Protocols.HTTP_1_1) {
            state |= CLOSE_REQ;
        }
        if (request.getRequestHeaders().contains(Headers.UPGRADE)) {
            state |= UPGRADE_REQUESTED;
        }
        if (request.getMethod().equals(Methods.CONNECT)) {
            // we treat CONNECT like upgrade requests
            state |= UPGRADE_REQUESTED;
        }
        // setup the client request conduits
        final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
        sourceChannel.setReadListener(clientReadListener);
        sourceChannel.resumeReads();
        ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();
        StreamSinkConduit conduit = originalSinkConduit;
        HttpRequestConduit httpRequestConduit = new HttpRequestConduit(conduit, bufferPool, request);
        httpClientExchange.setRequestConduit(httpRequestConduit);
        conduit = httpRequestConduit;
        String fixedLengthString = request.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
        String transferEncodingString = request.getRequestHeaders().getLast(Headers.TRANSFER_ENCODING);
        boolean hasContent = true;
        if (fixedLengthString != null) {
            try {
                long length = Long.parseLong(fixedLengthString);
                conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest);
                hasContent = length != 0;
            } catch (NumberFormatException e) {
                handleError(e);
                return;
            }
        } else if (transferEncodingString != null) {
            if (!transferEncodingString.toLowerCase(Locale.ENGLISH).contains(Headers.CHUNKED.toString())) {
                handleError(UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString));
                return;
            }
            conduit = new ChunkedStreamSinkConduit(conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange);
        } else {
            conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest);
            hasContent = false;
        }
        sinkChannel.setConduit(conduit);
        httpClientExchange.invokeReadReadyCallback();
        if (!hasContent) {
            // if there is no content we flush the response channel.
            // otherwise it is up to the user
            try {
                sinkChannel.shutdownWrites();
                if (!sinkChannel.flush()) {
                    sinkChannel.setWriteListener(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler<ConduitStreamSinkChannel>() {

                        @Override
                        public void handleException(ConduitStreamSinkChannel channel, IOException exception) {
                            handleError(exception);
                        }
                    }));
                    sinkChannel.resumeWrites();
                }
            } catch (Throwable t) {
                handleError(t);
            }
        }
    }

    private void handleError(Throwable exception) {
        if (exception instanceof IOException) {
            handleError((IOException) exception);
        } else {
            handleError(new IOException(exception));
        }
    }

    private void handleError(IOException exception) {
        UndertowLogger.REQUEST_IO_LOGGER.ioException(exception);
        currentRequest.setFailed(exception);
        currentRequest = null;
        pendingResponse = null;
        safeClose(connection);
    }

    public StreamConnection performUpgrade() throws IOException {
        log.debugf("connection to %s is being upgraded", getPeerAddress());
        // Upgrade the connection
        // Set the upgraded flag already to prevent new requests after this one
        if (allAreSet(state, UPGRADED | CLOSE_REQ | CLOSED)) {
            throw new IOException(UndertowClientMessages.MESSAGES.connectionClosed());
        }
        state |= UPGRADED;
        connection.getSinkChannel().setConduit(originalSinkConduit);
        connection.getSourceChannel().setConduit(pushBackStreamSourceConduit);
        return connection;
    }

    public void close() throws IOException {
        log.debugf("close called on connection to %s", getPeerAddress());
        if (http2Delegate != null) {
            http2Delegate.close();
        }
        if (anyAreSet(state, CLOSED)) {
            return;
        }
        state |= CLOSED | CLOSE_REQ;
        ConnectionUtils.cleanClose(connection);
    }

    /**
     * Notification that the current request is finished
     */
    public void exchangeDone() {
        log.debugf("exchange complete in connection to %s", getPeerAddress());
        connection.getSinkChannel().setConduit(originalSinkConduit);
        connection.getSourceChannel().setConduit(pushBackStreamSourceConduit);
        connection.getSinkChannel().suspendWrites();
        connection.getSinkChannel().setWriteListener(null);
        if (anyAreSet(state, CLOSE_REQ)) {
            currentRequest = null;
            pendingResponse = null;
            this.state |= CLOSED;
            safeClose(connection);
        } else if (anyAreSet(state, UPGRADE_REQUESTED)) {
            connection.getSourceChannel().suspendReads();
            currentRequest = null;
            pendingResponse = null;
            return;
        }
        currentRequest = null;
        pendingResponse = null;
        HttpClientExchange next = pendingQueue.poll();
        if (next == null) {
            // we resume reads, so if the target goes away we get notified
            connection.getSourceChannel().setReadListener(clientReadListener);
            connection.getSourceChannel().resumeReads();
        } else {
            initiateRequest(next);
        }
    }

    public void requestDataSent() {
        if (http2UpgradeReceived) {
            doHttp2Upgrade();
        }
    }

    clreplaced ClientReadListener implements ChannelListener<StreamSourceChannel> {

        public void handleEvent(StreamSourceChannel channel) {
            HttpResponseBuilder builder = pendingResponse;
            final PooledByteBuffer pooled = bufferPool.allocate();
            final ByteBuffer buffer = pooled.getBuffer();
            boolean free = true;
            try {
                if (builder == null) {
                    // read ready when no request pending
                    buffer.clear();
                    try {
                        int res = channel.read(buffer);
                        if (res == -1) {
                            UndertowLogger.CLIENT_LOGGER.debugf("Connection to %s was closed by the target server", connection.getPeerAddress());
                            safeClose(HttpClientConnection.this);
                        } else if (res != 0) {
                            UndertowLogger.CLIENT_LOGGER.debugf("Target server %s sent unexpected data when no request pending, closing connection", connection.getPeerAddress());
                            safeClose(HttpClientConnection.this);
                        }
                    // otherwise it is a spurious notification
                    } catch (IOException e) {
                        if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) {
                            UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException");
                        }
                        safeClose(connection);
                    }
                    return;
                }
                final ResponseParseState state = builder.getParseState();
                int res;
                do {
                    buffer.clear();
                    try {
                        res = channel.read(buffer);
                    } catch (IOException e) {
                        if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) {
                            UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException");
                        }
                        try {
                            if (currentRequest != null) {
                                currentRequest.setFailed(e);
                                currentRequest = null;
                            }
                            pendingResponse = null;
                        } finally {
                            safeClose(channel, HttpClientConnection.this);
                        }
                        return;
                    }
                    if (res == 0) {
                        if (!channel.isReadResumed()) {
                            channel.getReadSetter().set(this);
                            channel.resumeReads();
                        }
                        return;
                    } else if (res == -1) {
                        channel.suspendReads();
                        try {
                            // Cancel the current active request
                            if (currentRequest != null) {
                                currentRequest.setFailed(new IOException(MESSAGES.connectionClosed()));
                                currentRequest = null;
                            }
                            pendingResponse = null;
                        } finally {
                            safeClose(HttpClientConnection.this);
                        }
                        return;
                    }
                    buffer.flip();
                    HttpResponseParser.INSTANCE.handle(buffer, state, builder);
                    if (buffer.hasRemaining()) {
                        free = false;
                        pushBackStreamSourceConduit.pushBack(new PooledAdaptor(pooled));
                    }
                } while (!state.isComplete());
                final ClientResponse response = builder.build();
                String connectionString = response.getResponseHeaders().getFirst(Headers.CONNECTION);
                // check if an upgrade worked
                if (anyAreSet(HttpClientConnection.this.state, UPGRADE_REQUESTED)) {
                    if ((connectionString == null || !Headers.UPGRADE.equalToString(connectionString)) && !response.getResponseHeaders().contains(Headers.UPGRADE)) {
                        if (!currentRequest.getRequest().getMethod().equals(Methods.CONNECT) || response.getResponseCode() != 200) {
                            // make sure it was not actually a connect request
                            // just unset the upgrade requested flag
                            HttpClientConnection.this.state &= ~UPGRADE_REQUESTED;
                        }
                    }
                }
                boolean close = false;
                if (connectionString != null) {
                    if (Headers.CLOSE.equalToString(connectionString)) {
                        close = true;
                    } else if (!response.getProtocol().equals(Protocols.HTTP_1_1)) {
                        if (!Headers.KEEP_ALIVE.equalToString(connectionString)) {
                            close = true;
                        }
                    }
                } else if (!response.getProtocol().equals(Protocols.HTTP_1_1)) {
                    close = true;
                }
                if (close) {
                    HttpClientConnection.this.state |= CLOSE_REQ;
                    // we are going to close, kill any queued connections
                    HttpClientExchange ex = pendingQueue.poll();
                    while (ex != null) {
                        ex.setFailed(new IOException(UndertowClientMessages.MESSAGES.connectionClosed()));
                        ex = pendingQueue.poll();
                    }
                }
                if (response.getResponseCode() == StatusCodes.SWITCHING_PROTOCOLS && Http2Channel.CLEARTEXT_UPGRADE_STRING.equals(response.getResponseHeaders().getFirst(Headers.UPGRADE))) {
                    // http2 upgrade
                    http2UpgradeReceived = true;
                    if (currentRequest.isRequestDataSent()) {
                        doHttp2Upgrade();
                    }
                } else if (builder.getStatusCode() == StatusCodes.CONTINUE) {
                    pendingResponse = new HttpResponseBuilder();
                    currentRequest.setContinueResponse(response);
                } else {
                    prepareResponseChannel(response, currentRequest);
                    channel.getReadSetter().set(null);
                    channel.suspendReads();
                    pendingResponse = null;
                    currentRequest.setResponse(response);
                    if (response.getResponseCode() == StatusCodes.EXPECTATION_FAILED) {
                        if (HttpContinue.requiresContinueResponse(currentRequest.getRequest().getRequestHeaders())) {
                            HttpClientConnection.this.state |= CLOSE_REQ;
                            ConduitStreamSinkChannel sinkChannel = HttpClientConnection.this.connection.getSinkChannel();
                            sinkChannel.shutdownWrites();
                            if (!sinkChannel.flush()) {
                                sinkChannel.setWriteListener(ChannelListeners.flushingChannelListener(null, null));
                                sinkChannel.resumeWrites();
                            }
                            if (currentRequest != null) {
                                // we need the null check as flushing the response may have terminated the request
                                currentRequest.terminateRequest();
                            }
                        }
                    }
                }
            } catch (Throwable t) {
                UndertowLogger.CLIENT_LOGGER.exceptionProcessingRequest(t);
                safeClose(connection);
                if (currentRequest != null) {
                    currentRequest.setFailed(new IOException(t));
                }
            } finally {
                if (free) {
                    pooled.close();
                    pooledBuffer = null;
                } else {
                    pooledBuffer = pooled;
                }
            }
        }
    }

    protected void doHttp2Upgrade() {
        try {
            StreamConnection connectedStreamChannel = this.performUpgrade();
            Http2Channel http2Channel = new Http2Channel(connectedStreamChannel, null, bufferPool, null, true, true, options);
            Http2ClientConnection http2ClientConnection = new Http2ClientConnection(http2Channel, currentRequest.getResponseCallback(), currentRequest.getRequest(), currentRequest.getRequest().getRequestHeaders().getFirst(Headers.HOST), clientStatistics, false);
            http2ClientConnection.getCloseSetter().set(new ChannelListener<ClientConnection>() {

                @Override
                public void handleEvent(ClientConnection channel) {
                    ChannelListeners.invokeChannelListener(HttpClientConnection.this, HttpClientConnection.this.closeSetter.get());
                }
            });
            http2Delegate = http2ClientConnection;
            // make sure the read listener is immediately invoked, as it may not happen if data is pushed back
            connectedStreamChannel.getSourceChannel().wakeupReads();
            currentRequest = null;
            pendingResponse = null;
        } catch (IOException e) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
            safeClose(this);
        }
    }

    private void prepareResponseChannel(ClientResponse response, ClientExchange exchange) {
        String encoding = response.getResponseHeaders().getLast(Headers.TRANSFER_ENCODING);
        boolean chunked = encoding != null && Headers.CHUNKED.equals(new HttpString(encoding));
        String length = response.getResponseHeaders().getFirst(Headers.CONTENT_LENGTH);
        if (exchange.getRequest().getMethod().equals(Methods.HEAD)) {
            connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), 0, responseFinishedListener));
        } else if (chunked) {
            connection.getSourceChannel().setConduit(new ChunkedStreamSourceConduit(connection.getSourceChannel().getConduit(), pushBackStreamSourceConduit, bufferPool, responseFinishedListener, exchange, connection));
        } else if (length != null) {
            try {
                long contentLength = Long.parseLong(length);
                connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), contentLength, responseFinishedListener));
            } catch (NumberFormatException e) {
                handleError(e);
                throw e;
            }
        } else if (response.getProtocol().equals(Protocols.HTTP_1_1) && !Connectors.isEnreplacedyBodyAllowed(response.getResponseCode())) {
            connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), 0, responseFinishedListener));
        } else {
            connection.getSourceChannel().setConduit(new FinishableStreamSourceConduit(connection.getSourceChannel().getConduit(), responseFinishedListener));
            state |= CLOSE_REQ;
        }
    }

    private clreplaced ClientStatisticsImpl implements ClientStatistics {

        @Override
        public long getRequests() {
            return requestCount;
        }

        @Override
        public long getRead() {
            return read;
        }

        @Override
        public long getWritten() {
            return written;
        }

        @Override
        public void reset() {
            read = 0;
            written = 0;
            requestCount = 0;
        }
    }
}

19 View Complete Implementation : XnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
/**
 * {@link io.netty.channel.socket.SocketChannel} which uses XNIO.
 *
 * @author <a href="mailto:[email protected]">Norman Maurer</a>
 */
public clreplaced XnioSocketChannel extends AbstractXnioSocketChannel {

    private final OptionMap.Builder options = OptionMap.builder();

    private volatile StreamConnection channel;

    public XnioSocketChannel() {
        super(null);
        config().setTcpNoDelay(true);
    }

    @Override
    protected AbstractXnioUnsafe newUnsafe() {
        return new XnioUnsafe();
    }

    @Override
    protected <T> void setOption0(Option<T> option, T value) throws IOException {
        if (channel == null) {
            options.set(option, value);
        } else {
            channel.setOption(option, value);
        }
    }

    @Override
    protected <T> T getOption0(Option<T> option) throws IOException {
        if (channel == null) {
            return options.getMap().get(option);
        } else {
            return channel.getOption(option);
        }
    }

    @Override
    protected StreamConnection connection() {
        return channel;
    }

    @Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        throw new UnsupportedOperationException("Not supported to bind in a separate step");
    }

    private final clreplaced XnioUnsafe extends AbstractXnioUnsafe {

        @Override
        public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
            if (!ensureOpen(promise)) {
                return;
            }
            final boolean wasActive = isActive();
            XnioIoThread thread = ((XnioEventLoop) eventLoop()).ioThread();
            IoFuture<StreamConnection> future;
            if (localAddress == null) {
                future = thread.openStreamConnection(remoteAddress, null, null, options.getMap());
            } else {
                future = thread.openStreamConnection(localAddress, remoteAddress, null, null, options.getMap());
            }
            promise.addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if (channelFuture.isSuccess()) {
                        if (!wasActive && isActive()) {
                            pipeline().fireChannelActive();
                        }
                    } else {
                        closeIfClosed();
                    }
                }
            });
            future.addNotifier(new IoFuture.Notifier<StreamConnection, ChannelPromise>() {

                @Override
                public void notify(IoFuture<? extends StreamConnection> ioFuture, ChannelPromise promise) {
                    IoFuture.Status status = ioFuture.getStatus();
                    if (status == IoFuture.Status.DONE) {
                        try {
                            channel = ioFuture.get();
                            channel.getSourceChannel().getReadSetter().set(new ReadListener());
                            promise.setSuccess();
                            channel.getSourceChannel().resumeReads();
                        } catch (Throwable cause) {
                            promise.setFailure(cause);
                        }
                    } else {
                        Exception error;
                        if (status == IoFuture.Status.FAILED) {
                            error = ioFuture.getException();
                        } else {
                            error = new CancellationException();
                        }
                        promise.setFailure(error);
                    }
                }
            }, promise);
        }
    }
}

19 View Complete Implementation : Hybi08Handshake.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public WebSocketChannel createChannel(final WebSocketHttpExchange exchange, final StreamConnection channel, final ByteBufferPool pool) {
    List<ExtensionFunction> extensionFunctions = initExtensions(exchange);
    return new WebSocket08Channel(channel, pool, getWebSocketLocation(exchange), exchange.getResponseHeader(Headers.SEC_WEB_SOCKET_PROTOCOL_STRING), false, !extensionFunctions.isEmpty(), CompositeExtensionFunction.compose(extensionFunctions), exchange.getPeerConnections(), exchange.getOptions());
}

19 View Complete Implementation : QueuedNioTcpServer2.java
Copyright Apache License 2.0
Author : xnio
public StreamConnection accept() throws IOException {
    final WorkerThread current = WorkerThread.getCurrent();
    if (current == null) {
        return null;
    }
    final Queue<StreamConnection> socketChannels = acceptQueues.get(current.getNumber());
    final StreamConnection connection = socketChannels.poll();
    if (connection == null) {
        if (!realServer.isOpen()) {
            throw new ClosedChannelException();
        }
    }
    return connection;
}

19 View Complete Implementation : JsseSslConnection.java
Copyright Apache License 2.0
Author : xnio
public final clreplaced JsseSslConnection extends SslConnection {

    private final StreamConnection streamConnection;

    private final JsseStreamConduit conduit;

    private final ChannelListener.SimpleSetter<SslConnection> handshakeSetter = new ChannelListener.SimpleSetter<>();

    public JsseSslConnection(final StreamConnection streamConnection, final SSLEngine engine) {
        this(streamConnection, engine, JsseXnioSsl.bufferPool, JsseXnioSsl.bufferPool);
    }

    JsseSslConnection(final StreamConnection streamConnection, final SSLEngine engine, final Pool<ByteBuffer> socketBufferPool, final Pool<ByteBuffer> applicationBufferPool) {
        super(streamConnection.getIoThread());
        this.streamConnection = streamConnection;
        conduit = new JsseStreamConduit(this, engine, streamConnection.getSourceChannel().getConduit(), streamConnection.getSinkChannel().getConduit(), socketBufferPool, applicationBufferPool);
        setSourceConduit(conduit);
        setSinkConduit(conduit);
    }

    public void startHandshake() throws IOException {
        conduit.beginHandshake();
    }

    public SSLSession getSslSession() {
        return conduit.getSslSession();
    }

    protected void closeAction() throws IOException {
        try {
            if (!conduit.isWriteShutdown()) {
                conduit.terminateWrites();
            }
            if (!conduit.isReadShutdown()) {
                conduit.terminateReads();
            }
            conduit.flush();
            conduit.markTerminated();
            streamConnection.close();
        } catch (Throwable t) {
            // just make sure the connection is not left inconsistent
            try {
                if (!conduit.isReadShutdown()) {
                    conduit.terminateReads();
                }
            } catch (Throwable ignored) {
            }
            try {
                conduit.markTerminated();
                streamConnection.close();
            } catch (Throwable ignored) {
            }
            throw t;
        }
    }

    protected void notifyWriteClosed() {
    }

    protected void notifyReadClosed() {
    }

    public SocketAddress getPeerAddress() {
        return streamConnection.getPeerAddress();
    }

    public SocketAddress getLocalAddress() {
        return streamConnection.getLocalAddress();
    }

    public ChannelListener.Setter<? extends SslConnection> getHandshakeSetter() {
        return handshakeSetter;
    }

    void invokeHandshakeListener() {
        ChannelListeners.invokeChannelListener(this, handshakeSetter.get());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            final SSLEngine engine = conduit.getEngine();
            try {
                return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
            } finally {
                engine.setNeedClientAuth(value == SslClientAuthMode.REQUIRED);
                engine.setWantClientAuth(value == SslClientAuthMode.REQUESTED);
            }
        } else if (option == Options.SECURE) {
            throw new IllegalArgumentException();
        } else {
            return streamConnection.setOption(option, value);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getOption(final Option<T> option) throws IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            final SSLEngine engine = conduit.getEngine();
            return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
        } else {
            return option == Options.SECURE ? option.cast(Boolean.valueOf(conduit.isTls())) : streamConnection.getOption(option);
        }
    }

    private static final Set<Option<?>> SUPPORTED_OPTIONS = Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create();

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supportsOption(final Option<?> option) {
        return SUPPORTED_OPTIONS.contains(option) || streamConnection.supportsOption(option);
    }

    @Override
    public boolean isOpen() {
        return streamConnection.isOpen();
    }

    @Override
    public boolean isWriteShutdown() {
        return streamConnection.isWriteShutdown();
    }

    @Override
    public boolean isReadShutdown() {
        return streamConnection.isReadShutdown();
    }

    public SSLEngine getEngine() {
        return conduit.getEngine();
    }
}

19 View Complete Implementation : WebSocketChannel.java
Copyright Apache License 2.0
Author : undertow-io
@Override
protected IdleTimeoutConduit createIdleTimeoutChannel(final StreamConnection connectedStreamChannel) {
    return new IdleTimeoutConduit(connectedStreamChannel) {

        @Override
        protected void doClose() {
            WebSockets.sendClose(CloseMessage.GOING_AWAY, null, WebSocketChannel.this, null);
        }
    };
}

19 View Complete Implementation : NioTcpConnectionTestCase.java
Copyright Apache License 2.0
Author : xnio
@Override
protected void resumeWrites(StreamConnection channel) {
    channel.getSinkChannel().resumeWrites();
}

19 View Complete Implementation : AbstractFramedChannel.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * A {@link org.xnio.channels.ConnectedChannel} which can be used to send and receive Frames.
 * <p>
 * This provides a common base for framed protocols such as websockets and SPDY
 *
 * @author Stuart Douglas
 */
public abstract clreplaced AbstractFramedChannel<C extends AbstractFramedChannel<C, R, S>, R extends AbstractFramedStreamSourceChannel<C, R, S>, S extends AbstractFramedStreamSinkChannel<C, R, S>> implements ConnectedChannel {

    /**
     * The maximum number of buffers we will queue before suspending reads and
     * waiting for the buffers to be consumed
     *
     * TODO: make the configurable
     */
    private final int maxQueuedBuffers;

    private final StreamConnection channel;

    private final IdleTimeoutConduit idleTimeoutConduit;

    private final ChannelListener.SimpleSetter<C> closeSetter;

    private final ChannelListener.SimpleSetter<C> receiveSetter;

    private final ByteBufferPool bufferPool;

    /**
     * Frame priority implementation. This is used to determine the order in which frames get sent
     */
    private final FramePriority<C, R, S> framePriority;

    /**
     * List of frames that are ready to send
     */
    private final List<S> pendingFrames = new LinkedList<>();

    /**
     * Frames that are not yet read to send.
     */
    private final Deque<S> heldFrames = new ArrayDeque<>();

    /**
     * new frames to be sent. These will be added to either the pending or held frames list
     * depending on the {@link #framePriority} implementation in use.
     */
    private final Deque<S> newFrames = new LinkedBlockingDeque<>();

    private volatile long frameDataRemaining;

    private volatile R receiver;

    private volatile boolean receivesSuspendedByUser = true;

    private volatile boolean receivesSuspendedTooManyQueuedMessages = false;

    private volatile boolean receivesSuspendedTooManyBuffers = false;

    @SuppressWarnings("unused")
    private volatile int readsBroken = 0;

    @SuppressWarnings("unused")
    private volatile int writesBroken = 0;

    private static final AtomicIntegerFieldUpdater<AbstractFramedChannel> readsBrokenUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractFramedChannel.clreplaced, "readsBroken");

    private static final AtomicIntegerFieldUpdater<AbstractFramedChannel> writesBrokenUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractFramedChannel.clreplaced, "writesBroken");

    private volatile ReferenceCountedPooled readData = null;

    private final List<ChannelListener<C>> closeTasks = new CopyOnWriteArrayList<>();

    private volatile boolean flushingSenders = false;

    private boolean partialRead = false;

    @SuppressWarnings("unused")
    private volatile int outstandingBuffers;

    private static final AtomicIntegerFieldUpdater<AbstractFramedChannel> outstandingBuffersUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractFramedChannel.clreplaced, "outstandingBuffers");

    private final LinkedBlockingDeque<Runnable> taskRunQueue = new LinkedBlockingDeque<>();

    private final Runnable taskRunQueueRunnable = new Runnable() {

        @Override
        public void run() {
            Runnable runnable;
            while ((runnable = taskRunQueue.poll()) != null) {
                runnable.run();
            }
        }
    };

    private final OptionMap settings;

    /**
     * If this is true then the flush() method must be called to queue writes. This is provided to support batching
     */
    private volatile boolean requireExplicitFlush = false;

    private volatile boolean readChannelDone = false;

    private final int queuedFrameHighWaterMark;

    private final int queuedFrameLowWaterMark;

    private final ReferenceCountedPooled.FreeNotifier freeNotifier = new ReferenceCountedPooled.FreeNotifier() {

        @Override
        public void freed() {
            int res = outstandingBuffersUpdater.decrementAndGet(AbstractFramedChannel.this);
            if (!receivesSuspendedByUser && res == maxQueuedBuffers - 1) {
                // we need to do the resume in the IO thread, as there is a risk of deadlock otherwise, as the calling thread is an application thread
                // and may hold a lock on a stream source channel, see UNDERTOW-1312
                getIoThread().execute(new Runnable() {

                    @Override
                    public void run() {
                        synchronized (AbstractFramedChannel.this) {
                            if (outstandingBuffersUpdater.get(AbstractFramedChannel.this) < maxQueuedBuffers) {
                                if (UndertowLogger.REQUEST_IO_LOGGER.isTraceEnabled()) {
                                    UndertowLogger.REQUEST_IO_LOGGER.tracef("Resuming reads on %s as buffers have been consumed", AbstractFramedChannel.this);
                                }
                                new UpdateResumeState(null, false, null).run();
                            }
                        }
                    }
                });
            }
        }
    };

    private static final ChannelListener<AbstractFramedChannel> DRAIN_LISTENER = new ChannelListener<AbstractFramedChannel>() {

        @Override
        public void handleEvent(AbstractFramedChannel channel) {
            try {
                AbstractFramedStreamSourceChannel stream = channel.receive();
                if (stream != null) {
                    UndertowLogger.REQUEST_IO_LOGGER.debugf("Draining channel %s as no receive listener has been set", stream);
                    stream.getReadSetter().set(ChannelListeners.drainListener(Long.MAX_VALUE, null, null));
                    stream.wakeupReads();
                }
            } catch (IOException | RuntimeException | Error e) {
                IoUtils.safeClose(channel);
            }
        }
    };

    /**
     * Create a new {@link io.undertow.server.protocol.framed.AbstractFramedChannel}
     * 8
     *  @param connectedStreamChannel The {@link org.xnio.channels.ConnectedStreamChannel} over which the Frames should get send and received.
     *                               Be aware that it already must be "upgraded".
     * @param bufferPool             The {@link ByteBufferPool} which will be used to acquire {@link ByteBuffer}'s from.
     * @param framePriority
     * @param settings               The settings
     */
    protected AbstractFramedChannel(final StreamConnection connectedStreamChannel, ByteBufferPool bufferPool, FramePriority<C, R, S> framePriority, final PooledByteBuffer readData, OptionMap settings) {
        this.framePriority = framePriority;
        this.maxQueuedBuffers = settings.get(UndertowOptions.MAX_QUEUED_READ_BUFFERS, 10);
        this.settings = settings;
        if (readData != null) {
            if (readData.getBuffer().hasRemaining()) {
                this.readData = new ReferenceCountedPooled(readData, 1);
            } else {
                readData.close();
            }
        }
        if (bufferPool == null) {
            throw UndertowMessages.MESSAGES.argumentCannotBeNull("bufferPool");
        }
        if (connectedStreamChannel == null) {
            throw UndertowMessages.MESSAGES.argumentCannotBeNull("connectedStreamChannel");
        }
        IdleTimeoutConduit idle = createIdleTimeoutChannel(connectedStreamChannel);
        connectedStreamChannel.getSourceChannel().setConduit(idle);
        connectedStreamChannel.getSinkChannel().setConduit(idle);
        this.idleTimeoutConduit = idle;
        this.channel = connectedStreamChannel;
        this.bufferPool = bufferPool;
        closeSetter = new ChannelListener.SimpleSetter<>();
        receiveSetter = new ChannelListener.SimpleSetter<>();
        channel.getSourceChannel().getReadSetter().set(null);
        channel.getSourceChannel().suspendReads();
        channel.getSourceChannel().getReadSetter().set(new FrameReadListener());
        connectedStreamChannel.getSinkChannel().getWriteSetter().set(new FrameWriteListener());
        FrameCloseListener closeListener = new FrameCloseListener();
        connectedStreamChannel.getSinkChannel().getCloseSetter().set(closeListener);
        connectedStreamChannel.getSourceChannel().getCloseSetter().set(closeListener);
        this.queuedFrameHighWaterMark = settings.get(UndertowOptions.QUEUED_FRAMES_HIGH_WATER_MARK, 50);
        this.queuedFrameLowWaterMark = settings.get(UndertowOptions.QUEUED_FRAMES_LOW_WATER_MARK, 10);
    }

    protected IdleTimeoutConduit createIdleTimeoutChannel(StreamConnection connectedStreamChannel) {
        return new IdleTimeoutConduit(connectedStreamChannel);
    }

    void runInIoThread(Runnable task) {
        this.taskRunQueue.add(task);
        try {
            getIoThread().execute(taskRunQueueRunnable);
        } catch (RejectedExecutionException e) {
            // thread is shutting down
            ShutdownFallbackExecutor.execute(taskRunQueueRunnable);
        }
    }

    /**
     * Get the buffer pool for this connection.
     *
     * @return the buffer pool for this connection
     */
    public ByteBufferPool getBufferPool() {
        return bufferPool;
    }

    @Override
    public SocketAddress getLocalAddress() {
        return channel.getLocalAddress();
    }

    @Override
    public <A extends SocketAddress> A getLocalAddress(Clreplaced<A> type) {
        return channel.getLocalAddress(type);
    }

    @Override
    public XnioWorker getWorker() {
        return channel.getWorker();
    }

    @Override
    public XnioIoThread getIoThread() {
        return channel.getIoThread();
    }

    @Override
    public boolean supportsOption(Option<?> option) {
        return channel.supportsOption(option);
    }

    @Override
    public <T> T getOption(Option<T> option) throws IOException {
        return channel.getOption(option);
    }

    @Override
    public <T> T setOption(Option<T> option, T value) throws IOException {
        return channel.setOption(option, value);
    }

    @Override
    public boolean isOpen() {
        return channel.isOpen();
    }

    @Override
    public SocketAddress getPeerAddress() {
        return channel.getPeerAddress();
    }

    @Override
    public <A extends SocketAddress> A getPeerAddress(Clreplaced<A> type) {
        return channel.getPeerAddress(type);
    }

    /**
     * Get the source address of the Channel.
     *
     * @return the source address of the Channel
     */
    public InetSocketAddress getSourceAddress() {
        return getPeerAddress(InetSocketAddress.clreplaced);
    }

    /**
     * Get the destination address of the Channel.
     *
     * @return the destination address of the Channel
     */
    public InetSocketAddress getDestinationAddress() {
        return getLocalAddress(InetSocketAddress.clreplaced);
    }

    /**
     * receive method, returns null if no frame is ready. Otherwise returns a
     * channel that can be used to read the frame contents.
     * <p>
     * Calling this method can also have the side effect of making additional data available to
     * existing source channels. In general if you suspend receives or don't have some other way
     * of calling this method then it can prevent frame channels for being fully consumed.
     */
    public R receive() throws IOException {
        // store in a local variable to prevent invoking lastDataRead twice
        boolean receivedMinusOne = false;
        try {
            synchronized (this) {
                if (readChannelDone && receiver == null) {
                    // we have received the last frame, we just shut down and return
                    // it would probably make more sense to have the last channel responsible for this
                    // however it is much simpler just to have it here
                    if (readData != null) {
                        readData.close();
                        readData = null;
                    }
                    channel.getSourceChannel().suspendReads();
                    channel.getSourceChannel().shutdownReads();
                    return null;
                }
                partialRead = false;
                boolean requiresReinvoke = false;
                int reinvokeDataRemaining = 0;
                ReferenceCountedPooled pooled = this.readData;
                boolean hasData = false;
                if (pooled == null) {
                    pooled = allocateReferenceCountedBuffer();
                    if (pooled == null) {
                        return null;
                    }
                } else if (pooled.isFreed()) {
                    // we attempt to re-used an existing buffer
                    if (!pooled.tryUnfree()) {
                        pooled = allocateReferenceCountedBuffer();
                        if (pooled == null) {
                            return null;
                        }
                    }
                    pooled.getBuffer().clear();
                } else {
                    hasData = pooled.getBuffer().hasRemaining();
                    pooled.getBuffer().compact();
                }
                boolean forceFree = false;
                int read = 0;
                try {
                    read = channel.getSourceChannel().read(pooled.getBuffer());
                    if (read == 0 && !hasData) {
                        // no data, we just free the buffer
                        forceFree = true;
                        return null;
                    } else if (read == -1 && !hasData) {
                        forceFree = true;
                        receivedMinusOne = readChannelDone = true;
                        return null;
                    } else if (isLastFrameReceived() && frameDataRemaining == 0) {
                        // we got data, although we should have received the last frame
                        forceFree = true;
                        markReadsBroken(new ClosedChannelException());
                    }
                    pooled.getBuffer().flip();
                    if (read == -1) {
                        requiresReinvoke = true;
                        reinvokeDataRemaining = pooled.getBuffer().remaining();
                    }
                    if (frameDataRemaining > 0) {
                        if (frameDataRemaining >= pooled.getBuffer().remaining()) {
                            frameDataRemaining -= pooled.getBuffer().remaining();
                            if (receiver != null) {
                                // we still create a pooled view, this means that if the buffer is still active we can re-used it
                                // which prevents attacks based on sending lots of small fragments
                                PooledByteBuffer frameData = pooled.createView();
                                receiver.dataReady(null, frameData);
                            } else {
                                // we are dropping a frame
                                pooled.close();
                                readData = null;
                            }
                            if (frameDataRemaining == 0) {
                                receiver = null;
                            }
                            return null;
                        } else {
                            PooledByteBuffer frameData = pooled.createView((int) frameDataRemaining);
                            frameDataRemaining = 0;
                            if (receiver != null) {
                                receiver.dataReady(null, frameData);
                            } else {
                                // we are dropping the frame
                                frameData.close();
                            }
                            receiver = null;
                        }
                        // if we read data into a frame we just return immediately, even if there is more remaining
                        // see https://issues.jboss.org/browse/UNDERTOW-410
                        // basically if we don't do this we loose some message ordering semantics
                        // as the second message may be processed before the first one
                        // this is problematic for HTTPS, where the read listener may also be invoked by a queued task
                        // and not by the selector mechanism
                        return null;
                    }
                    FrameHeaderData data = parseFrame(pooled.getBuffer());
                    if (data != null) {
                        PooledByteBuffer frameData;
                        if (data.getFrameLength() >= pooled.getBuffer().remaining()) {
                            frameDataRemaining = data.getFrameLength() - pooled.getBuffer().remaining();
                            frameData = pooled.createView();
                            pooled.getBuffer().position(pooled.getBuffer().limit());
                        } else {
                            frameData = pooled.createView((int) data.getFrameLength());
                        }
                        AbstractFramedStreamSourceChannel<?, ?, ?> existing = data.getExistingChannel();
                        if (existing != null) {
                            if (data.getFrameLength() > frameData.getBuffer().remaining()) {
                                receiver = (R) existing;
                            }
                            existing.dataReady(data, frameData);
                            if (isLastFrameReceived()) {
                                handleLastFrame(existing);
                            }
                            return null;
                        } else {
                            boolean moreData = data.getFrameLength() > frameData.getBuffer().remaining();
                            R newChannel = createChannel(data, frameData);
                            if (newChannel != null) {
                                if (moreData) {
                                    receiver = newChannel;
                                }
                                if (isLastFrameReceived()) {
                                    handleLastFrame(newChannel);
                                }
                            } else {
                                frameData.close();
                            }
                            return newChannel;
                        }
                    } else {
                        // we set partial read to true so the read listener knows not to immediately call receive again
                        partialRead = true;
                    }
                    return null;
                } catch (IOException | RuntimeException | Error e) {
                    // something has code wrong with parsing, close the read side
                    // we don't close the write side, as the underlying implementation will most likely want to send an error
                    markReadsBroken(e);
                    forceFree = true;
                    throw e;
                } finally {
                    // if the receive caused the channel to break the close listener may be have been called
                    // which will make readData null
                    if (readData != null) {
                        if (!pooled.getBuffer().hasRemaining() || forceFree) {
                            if (pooled.getBuffer().capacity() < 1024 || forceFree) {
                                // if there is less than 1k left we don't allow it to be re-aquired
                                readData = null;
                            }
                            // even though this is freed we may un-free it if we get a new packet
                            // this prevents many small reads resulting in a large number of allocated buffers
                            pooled.close();
                        }
                    }
                    if (requiresReinvoke) {
                        if (readData != null && !readData.isFreed()) {
                            if (readData.getBuffer().remaining() == reinvokeDataRemaining) {
                                readData.close();
                                readData = null;
                                UndertowLogger.REQUEST_IO_LOGGER.debugf("Partial message read before connection close %s", this);
                            }
                        }
                        channel.getSourceChannel().wakeupReads();
                    }
                }
            }
        } finally {
            // read receivedMinusOne, and not readChannelDone
            // to prevent lastDataRead being invoked twice in case of
            // two concurrent receive invocations
            if (receivedMinusOne) {
                lastDataRead();
            }
        }
    }

    /**
     * Called when the last frame has been received (note that their may still be data from the last frame than needs to be read)
     * @param newChannel The channel that received the last frame
     */
    private void handleLastFrame(AbstractFramedStreamSourceChannel newChannel) {
        // make a defensive copy
        Set<AbstractFramedStreamSourceChannel<C, R, S>> receivers = new HashSet<>(getReceivers());
        for (AbstractFramedStreamSourceChannel<C, R, S> r : receivers) {
            if (r != newChannel) {
                r.markStreamBroken();
            }
        }
    }

    private ReferenceCountedPooled allocateReferenceCountedBuffer() {
        if (maxQueuedBuffers > 0) {
            int expect;
            do {
                expect = outstandingBuffersUpdater.get(this);
                if (expect == maxQueuedBuffers) {
                    synchronized (this) {
                        // we need to re-read in a sync block, to prevent races
                        expect = outstandingBuffersUpdater.get(this);
                        if (expect == maxQueuedBuffers) {
                            if (UndertowLogger.REQUEST_IO_LOGGER.isTraceEnabled()) {
                                UndertowLogger.REQUEST_IO_LOGGER.tracef("Suspending reads on %s due to too many outstanding buffers", this);
                            }
                            getIoThread().execute(new UpdateResumeState(null, true, null));
                            return null;
                        }
                    }
                }
            } while (!outstandingBuffersUpdater.compareAndSet(this, expect, expect + 1));
        }
        PooledByteBuffer buf = bufferPool.allocate();
        return this.readData = new ReferenceCountedPooled(buf, 1, maxQueuedBuffers > 0 ? freeNotifier : null);
    }

    /**
     * Method than is invoked when read() returns -1.
     */
    protected void lastDataRead() {
    }

    /**
     * Method that creates the actual stream source channel implementation that is in use.
     *
     * @param frameHeaderData The header data, as returned by {@link #parseFrame(java.nio.ByteBuffer)}
     * @param frameData       Any additional data for the frame that has already been read. This may not be the complete frame contents
     * @return A new stream source channel
     */
    protected abstract R createChannel(FrameHeaderData frameHeaderData, PooledByteBuffer frameData) throws IOException;

    /**
     * Attempts to parse an incoming frame header from the data in the buffer.
     *
     * @param data The data that has been read from the channel
     * @return The frame header data, or <code>null</code> if the data was incomplete
     * @throws IOException If the data could not be parsed.
     */
    protected abstract FrameHeaderData parseFrame(ByteBuffer data) throws IOException;

    protected synchronized void recalculateHeldFrames() throws IOException {
        if (!heldFrames.isEmpty()) {
            framePriority.frameAdded(null, pendingFrames, heldFrames);
            flushSenders();
        }
    }

    /**
     * Flushes all ready stream sink conduits to the channel.
     * <p>
     * Frames will be batched up, to allow them all to be written out via a gathering
     * write. The {@link #framePriority} implementation will be invoked to decide which
     * frames are eligible for sending and in what order.
     */
    protected synchronized void flushSenders() {
        if (flushingSenders) {
            throw UndertowMessages.MESSAGES.recursiveCallToFlushingSenders();
        }
        flushingSenders = true;
        try {
            int toSend = 0;
            S frame;
            while ((frame = newFrames.poll()) != null) {
                frame.preWrite();
                if (framePriority.insertFrame(frame, pendingFrames)) {
                    if (!heldFrames.isEmpty()) {
                        framePriority.frameAdded(frame, pendingFrames, heldFrames);
                    }
                } else {
                    heldFrames.add(frame);
                }
            }
            boolean finalFrame = false;
            Lisreplacederator<S> it = pendingFrames.lisreplacederator();
            while (it.hasNext()) {
                S sender = it.next();
                if (sender.isReadyForFlush()) {
                    ++toSend;
                } else {
                    break;
                }
                if (sender.isLastFrame()) {
                    finalFrame = true;
                }
            }
            if (toSend == 0) {
                // if there is nothing to send we just attempt a flush on the underlying channel
                try {
                    if (channel.getSinkChannel().flush()) {
                        channel.getSinkChannel().suspendWrites();
                    }
                } catch (Throwable e) {
                    safeClose(channel);
                    markWritesBroken(e);
                }
                return;
            }
            ByteBuffer[] data = new ByteBuffer[toSend * 3];
            int j = 0;
            it = pendingFrames.lisreplacederator();
            try {
                while (j < toSend) {
                    S next = it.next();
                    // todo: rather than adding empty buffers just store the offsets
                    SendFrameHeader frameHeader = next.getFrameHeader();
                    PooledByteBuffer frameHeaderByteBuffer = frameHeader.getByteBuffer();
                    ByteBuffer frameTrailerBuffer = frameHeader.getTrailer();
                    data[j * 3] = frameHeaderByteBuffer != null ? frameHeaderByteBuffer.getBuffer() : Buffers.EMPTY_BYTE_BUFFER;
                    data[(j * 3) + 1] = next.getBuffer() == null ? Buffers.EMPTY_BYTE_BUFFER : next.getBuffer();
                    data[(j * 3) + 2] = frameTrailerBuffer != null ? frameTrailerBuffer : Buffers.EMPTY_BYTE_BUFFER;
                    ++j;
                }
                long toWrite = Buffers.remaining(data);
                long res;
                do {
                    res = channel.getSinkChannel().write(data);
                    toWrite -= res;
                } while (res > 0 && toWrite > 0);
                int max = toSend;
                while (max > 0) {
                    S sinkChannel = pendingFrames.get(0);
                    PooledByteBuffer frameHeaderByteBuffer = sinkChannel.getFrameHeader().getByteBuffer();
                    ByteBuffer frameTrailerBuffer = sinkChannel.getFrameHeader().getTrailer();
                    if (frameHeaderByteBuffer != null && frameHeaderByteBuffer.getBuffer().hasRemaining() || sinkChannel.getBuffer() != null && sinkChannel.getBuffer().hasRemaining() || frameTrailerBuffer != null && frameTrailerBuffer.hasRemaining()) {
                        break;
                    }
                    sinkChannel.flushComplete();
                    pendingFrames.remove(sinkChannel);
                    max--;
                }
                if (!pendingFrames.isEmpty() || !channel.getSinkChannel().flush()) {
                    channel.getSinkChannel().resumeWrites();
                } else {
                    channel.getSinkChannel().suspendWrites();
                }
                if (pendingFrames.isEmpty() && finalFrame) {
                    // all data has been sent. Close gracefully
                    channel.getSinkChannel().shutdownWrites();
                    if (!channel.getSinkChannel().flush()) {
                        channel.getSinkChannel().setWriteListener(ChannelListeners.flushingChannelListener(null, null));
                        channel.getSinkChannel().resumeWrites();
                    }
                } else if (pendingFrames.size() > queuedFrameHighWaterMark) {
                    new UpdateResumeState(null, null, true).run();
                } else if (receivesSuspendedTooManyQueuedMessages && pendingFrames.size() < queuedFrameLowWaterMark) {
                    new UpdateResumeState(null, null, false).run();
                }
            } catch (IOException | RuntimeException | Error e) {
                safeClose(channel);
                markWritesBroken(e);
            }
        } finally {
            flushingSenders = false;
            if (!newFrames.isEmpty()) {
                runInIoThread(new Runnable() {

                    @Override
                    public void run() {
                        flushSenders();
                    }
                });
            }
        }
    }

    void awaitWritable() throws IOException {
        this.channel.getSinkChannel().awaitWritable();
    }

    void awaitWritable(long time, TimeUnit unit) throws IOException {
        this.channel.getSinkChannel().awaitWritable(time, unit);
    }

    /**
     * Queues a new frame to be sent, and attempts a flush if this is the first frame in the new frame queue.
     * <p>
     * Depending on the {@link FramePriority} implementation in use the channel may or may not be added to the actual
     * pending queue
     *
     * @param channel The channel
     */
    protected void queueFrame(final S channel) throws IOException {
        replacedert !newFrames.contains(channel);
        if (isWritesBroken() || !this.channel.getSinkChannel().isOpen() || channel.isBroken() || !channel.isOpen()) {
            IoUtils.safeClose(channel);
            throw UndertowMessages.MESSAGES.channelIsClosed();
        }
        newFrames.add(channel);
        if (!requireExplicitFlush || channel.isBufferFull()) {
            flush();
        }
    }

    public void flush() {
        if (!flushingSenders) {
            if (channel.getIoThread() == Thread.currentThread()) {
                flushSenders();
            } else {
                runInIoThread(new Runnable() {

                    @Override
                    public void run() {
                        flushSenders();
                    }
                });
            }
        }
    }

    /**
     * Returns true if the protocol specific final frame has been received.
     *
     * @return <code>true</code> If the last frame has been received
     */
    protected abstract boolean isLastFrameReceived();

    /**
     * @return <code>true</code> If the last frame has been sent
     */
    protected abstract boolean isLastFrameSent();

    /**
     * Method that is invoked when the read side of the channel is broken. This generally happens on a protocol error.
     */
    protected abstract void handleBrokenSourceChannel(Throwable e);

    /**
     * Method that is invoked when then write side of a channel is broken. This generally happens on a protocol error.
     */
    protected abstract void handleBrokenSinkChannel(Throwable e);

    /**
     * Return the {@link org.xnio.ChannelListener.Setter} which will holds the {@link org.xnio.ChannelListener} that gets notified once a frame was
     * received.
     */
    public Setter<C> getReceiveSetter() {
        return receiveSetter;
    }

    /**
     * Suspend the receive of new frames via {@link #receive()}
     */
    public synchronized void suspendReceives() {
        receivesSuspendedByUser = true;
        getIoThread().execute(new UpdateResumeState(true, null, null));
    }

    /**
     * Resume the receive of new frames via {@link #receive()}
     */
    public synchronized void resumeReceives() {
        receivesSuspendedByUser = false;
        getIoThread().execute(new UpdateResumeState(false, null, null));
    }

    private void doResume() {
        if (readData != null && !readData.isFreed()) {
            channel.getSourceChannel().wakeupReads();
        } else {
            channel.getSourceChannel().resumeReads();
        }
    }

    public boolean isReceivesResumed() {
        return !receivesSuspendedByUser;
    }

    /**
     * Forcibly closes the {@link io.undertow.server.protocol.framed.AbstractFramedChannel}.
     */
    @Override
    public void close() throws IOException {
        synchronized (this) {
            if (UndertowLogger.REQUEST_IO_LOGGER.isTraceEnabled()) {
                UndertowLogger.REQUEST_IO_LOGGER.tracef(new ClosedChannelException(), "Channel %s is being closed", this);
            }
            safeClose(channel);
            if (readData != null) {
                readData.close();
                readData = null;
            }
        }
        closeSubChannels();
    }

    @Override
    public Setter<? extends AbstractFramedChannel> getCloseSetter() {
        return closeSetter;
    }

    /**
     * Called when a source sub channel fails to fulfil its contract, and leaves the channel in an inconsistent state.
     * <p>
     * The underlying read side will be forcibly closed.
     *
     * @param cause The possibly null cause
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected void markReadsBroken(Throwable cause) {
        if (readsBrokenUpdater.compareAndSet(this, 0, 1)) {
            if (UndertowLogger.REQUEST_IO_LOGGER.isDebugEnabled()) {
                UndertowLogger.REQUEST_IO_LOGGER.debugf(new ClosedChannelException(), "Marking reads broken on channel %s", this);
            }
            if (receiver != null) {
                receiver.markStreamBroken();
            }
            for (AbstractFramedStreamSourceChannel<C, R, S> r : new ArrayList<>(getReceivers())) {
                r.markStreamBroken();
            }
            handleBrokenSourceChannel(cause);
            safeClose(channel.getSourceChannel());
            closeSubChannels();
        }
    }

    /**
     * Method that is called when the channel is being forcibly closed, and all sub stream sink/source
     * channels should also be forcibly closed.
     */
    protected abstract void closeSubChannels();

    /**
     * Called when a sub channel fails to fulfil its contract, and leaves the channel in an inconsistent state.
     * <p>
     * The underlying channel will be closed, and any sub channels that have writes resumed will have their
     * listeners notified. It is expected that these listeners will then attempt to use the channel, and their standard
     * error handling logic will take over.
     *
     * @param cause The possibly null cause
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected void markWritesBroken(Throwable cause) {
        if (writesBrokenUpdater.compareAndSet(this, 0, 1)) {
            if (UndertowLogger.REQUEST_IO_LOGGER.isDebugEnabled()) {
                UndertowLogger.REQUEST_IO_LOGGER.debugf(new ClosedChannelException(), "Marking writes broken on channel %s", this);
            }
            handleBrokenSinkChannel(cause);
            safeClose(channel.getSinkChannel());
            synchronized (this) {
                for (final S channel : pendingFrames) {
                    channel.markBroken();
                }
                pendingFrames.clear();
                for (final S channel : newFrames) {
                    channel.markBroken();
                }
                newFrames.clear();
                for (final S channel : heldFrames) {
                    channel.markBroken();
                }
                heldFrames.clear();
            }
        }
    }

    protected boolean isWritesBroken() {
        return writesBrokenUpdater.get(this) != 0;
    }

    protected boolean isReadsBroken() {
        return readsBrokenUpdater.get(this) != 0;
    }

    void resumeWrites() {
        channel.getSinkChannel().resumeWrites();
    }

    void suspendWrites() {
        channel.getSinkChannel().suspendWrites();
    }

    void wakeupWrites() {
        channel.getSinkChannel().wakeupWrites();
    }

    StreamSourceChannel getSourceChannel() {
        return channel.getSourceChannel();
    }

    void notifyFrameReadComplete(AbstractFramedStreamSourceChannel<C, R, S> channel) {
    }

    /**
     * {@link org.xnio.ChannelListener} which delegates the read notification to the appropriate listener
     */
    private final clreplaced FrameReadListener implements ChannelListener<StreamSourceChannel> {

        @SuppressWarnings({ "unchecked", "rawtypes" })
        @Override
        public void handleEvent(final StreamSourceChannel channel) {
            // clear the task queue before reading
            Runnable runnable;
            while ((runnable = taskRunQueue.poll()) != null) {
                runnable.run();
            }
            final R receiver = AbstractFramedChannel.this.receiver;
            if ((readChannelDone || isReadsSuspended()) && receiver == null) {
                channel.suspendReads();
                return;
            } else {
                ChannelListener listener = receiveSetter.get();
                if (listener == null) {
                    listener = DRAIN_LISTENER;
                }
                UndertowLogger.REQUEST_IO_LOGGER.tracef("Invoking receive listener", receiver);
                ChannelListeners.invokeChannelListener(AbstractFramedChannel.this, listener);
            }
            final boolean partialRead;
            synchronized (AbstractFramedChannel.this) {
                partialRead = AbstractFramedChannel.this.partialRead;
            }
            if (readData != null && !readData.isFreed() && channel.isOpen() && !partialRead) {
                try {
                    runInIoThread(new Runnable() {

                        @Override
                        public void run() {
                            ChannelListeners.invokeChannelListener(channel, FrameReadListener.this);
                        }
                    });
                } catch (RejectedExecutionException e) {
                    IoUtils.safeClose(AbstractFramedChannel.this);
                }
            }
            synchronized (AbstractFramedChannel.this) {
                AbstractFramedChannel.this.partialRead = false;
            }
        }
    }

    private boolean isReadsSuspended() {
        return receivesSuspendedByUser || receivesSuspendedTooManyBuffers || receivesSuspendedTooManyQueuedMessages;
    }

    private clreplaced FrameWriteListener implements ChannelListener<StreamSinkChannel> {

        @Override
        public void handleEvent(final StreamSinkChannel channel) {
            flushSenders();
        }
    }

    /**
     * close listener, just goes through and activates any sub channels to make sure their listeners are invoked
     */
    private clreplaced FrameCloseListener implements ChannelListener<CloseableChannel> {

        private boolean sinkClosed;

        private boolean sourceClosed;

        @Override
        public void handleEvent(final CloseableChannel c) {
            if (Thread.currentThread() != c.getIoThread() && !c.getWorker().isShutdown()) {
                runInIoThread(new Runnable() {

                    @Override
                    public void run() {
                        ChannelListeners.invokeChannelListener(c, FrameCloseListener.this);
                    }
                });
                return;
            }
            if (c instanceof StreamSinkChannel) {
                sinkClosed = true;
            } else if (c instanceof StreamSourceChannel) {
                sourceClosed = true;
            }
            if (!sourceClosed || !sinkClosed) {
                // both sides need to be closed
                return;
            } else if (readData != null && !readData.isFreed()) {
                // we make sure there is no data left to receive, if there is then we invoke the receive listener
                runInIoThread(new Runnable() {

                    @Override
                    public void run() {
                        while (readData != null && !readData.isFreed()) {
                            int rem = readData.getBuffer().remaining();
                            ChannelListener listener = receiveSetter.get();
                            if (listener == null) {
                                listener = DRAIN_LISTENER;
                            }
                            ChannelListeners.invokeChannelListener(AbstractFramedChannel.this, listener);
                            if (!AbstractFramedChannel.this.isOpen()) {
                                break;
                            }
                            if (readData != null && rem == readData.getBuffer().remaining()) {
                                // make sure we are making progress
                                break;
                            }
                        }
                        handleEvent(c);
                    }
                });
                return;
            }
            R receiver = AbstractFramedChannel.this.receiver;
            try {
                if (receiver != null && receiver.isOpen() && receiver.isReadResumed()) {
                    ChannelListeners.invokeChannelListener(receiver, ((SimpleSetter) receiver.getReadSetter()).get());
                }
                final List<S> pendingFrames;
                final List<S> newFrames;
                final List<S> heldFrames;
                final List<AbstractFramedStreamSourceChannel<C, R, S>> receivers;
                synchronized (AbstractFramedChannel.this) {
                    pendingFrames = new ArrayList<>(AbstractFramedChannel.this.pendingFrames);
                    newFrames = new ArrayList<>(AbstractFramedChannel.this.newFrames);
                    heldFrames = new ArrayList<>(AbstractFramedChannel.this.heldFrames);
                    receivers = new ArrayList<>(getReceivers());
                }
                for (final S channel : pendingFrames) {
                    // if this was a clean shutdown there should not be any senders
                    channel.markBroken();
                }
                for (final S channel : newFrames) {
                    // if this was a clean shutdown there should not be any senders
                    channel.markBroken();
                }
                for (final S channel : heldFrames) {
                    // if this was a clean shutdown there should not be any senders
                    channel.markBroken();
                }
                for (AbstractFramedStreamSourceChannel<C, R, S> r : receivers) {
                    IoUtils.safeClose(r);
                }
            } finally {
                try {
                    for (ChannelListener<C> task : closeTasks) {
                        ChannelListeners.invokeChannelListener((C) AbstractFramedChannel.this, task);
                    }
                } finally {
                    synchronized (AbstractFramedChannel.this) {
                        closeSubChannels();
                        if (readData != null) {
                            readData.close();
                            readData = null;
                        }
                    }
                    ChannelListeners.invokeChannelListener((C) AbstractFramedChannel.this, closeSetter.get());
                }
            }
        }
    }

    protected abstract Collection<AbstractFramedStreamSourceChannel<C, R, S>> getReceivers();

    public void setIdleTimeout(long timeout) {
        idleTimeoutConduit.setIdleTimeout(timeout);
    }

    public long getIdleTimeout() {
        return idleTimeoutConduit.getIdleTimeout();
    }

    protected FramePriority<C, R, S> getFramePriority() {
        return framePriority;
    }

    public void addCloseTask(final ChannelListener<C> task) {
        closeTasks.add(task);
    }

    @Override
    public String toString() {
        return getClreplaced().getSimpleName() + " peer " + channel.getPeerAddress() + " local " + channel.getLocalAddress() + "[ " + (receiver == null ? "No Receiver" : receiver.toString()) + " " + pendingFrames.toString() + " -- " + heldFrames.toString() + " -- " + newFrames.toString() + "]";
    }

    protected StreamConnection getUnderlyingConnection() {
        return channel;
    }

    protected ChannelExceptionHandler<SuspendableWriteChannel> writeExceptionHandler() {
        return new ChannelExceptionHandler<SuspendableWriteChannel>() {

            @Override
            public void handleException(SuspendableWriteChannel channel, IOException exception) {
                markWritesBroken(exception);
            }
        };
    }

    public boolean isRequireExplicitFlush() {
        return requireExplicitFlush;
    }

    public void setRequireExplicitFlush(boolean requireExplicitFlush) {
        this.requireExplicitFlush = requireExplicitFlush;
    }

    protected OptionMap getSettings() {
        return settings;
    }

    private clreplaced UpdateResumeState implements Runnable {

        private final Boolean user;

        private final Boolean buffers;

        private final Boolean frames;

        private UpdateResumeState(Boolean user, Boolean buffers, Boolean frames) {
            this.user = user;
            this.buffers = buffers;
            this.frames = frames;
        }

        @Override
        public void run() {
            if (user != null) {
                receivesSuspendedByUser = user;
            }
            if (buffers != null) {
                receivesSuspendedTooManyBuffers = buffers;
            }
            if (frames != null) {
                receivesSuspendedTooManyQueuedMessages = frames;
            }
            if (receivesSuspendedByUser || receivesSuspendedTooManyQueuedMessages || receivesSuspendedTooManyBuffers) {
                channel.getSourceChannel().suspendReads();
            } else {
                doResume();
            }
        }
    }
}

19 View Complete Implementation : NioTcpConnectionTestCase.java
Copyright Apache License 2.0
Author : xnio
@Override
protected void setReadListener(StreamConnection channel, ChannelListener<ConduitStreamSourceChannel> readListener) {
    channel.getSourceChannel().setReadListener(readListener);
}

19 View Complete Implementation : WebConnectionImpl.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * @author Stuart Douglas
 */
public clreplaced WebConnectionImpl implements WebConnection {

    private final StreamConnection channel;

    private final UpgradeServletOutputStream outputStream;

    private final UpgradeServletInputStream inputStream;

    private final Executor ioExecutor;

    public WebConnectionImpl(final StreamConnection channel, ByteBufferPool bufferPool, Executor ioExecutor) {
        this.channel = channel;
        this.ioExecutor = ioExecutor;
        this.outputStream = new UpgradeServletOutputStream(channel.getSinkChannel(), ioExecutor);
        this.inputStream = new UpgradeServletInputStream(channel.getSourceChannel(), bufferPool, ioExecutor);
        channel.getCloseSetter().set(new ChannelListener<StreamConnection>() {

            @Override
            public void handleEvent(StreamConnection channel) {
                try {
                    close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return inputStream;
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return outputStream;
    }

    @Override
    public void close() throws Exception {
        try {
            outputStream.closeBlocking();
        } finally {
            IoUtils.safeClose(inputStream, channel);
        }
    }
}

19 View Complete Implementation : HttpOpenListener.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public void handleEvent(StreamConnection channel) {
    handleEvent(channel, null);
}

19 View Complete Implementation : WriteTimeoutStreamSinkConduit.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * Wrapper for write timeout. This should always be the first wrapper applied to the underlying channel.
 *
 * @author Stuart Douglas
 * @see org.xnio.Options#WRITE_TIMEOUT
 */
public final clreplaced WriteTimeoutStreamSinkConduit extends AbstractStreamSinkConduit<StreamSinkConduit> {

    private XnioExecutor.Key handle;

    private final StreamConnection connection;

    private volatile long expireTime = -1;

    private final OpenListener openListener;

    // we add 50ms to the timeout to make sure the underlying channel has actually timed out
    private static final int FUZZ_FACTOR = 50;

    private final Runnable timeoutCommand = new Runnable() {

        @Override
        public void run() {
            handle = null;
            if (expireTime == -1) {
                return;
            }
            long current = System.currentTimeMillis();
            if (current < expireTime) {
                // timeout has been bumped, re-schedule
                handle = WorkerUtils.executeAfter(getWriteThread(), timeoutCommand, (expireTime - current) + FUZZ_FACTOR, TimeUnit.MILLISECONDS);
                return;
            }
            UndertowLogger.REQUEST_LOGGER.tracef("Timing out channel %s due to inactivity", connection.getSinkChannel());
            IoUtils.safeClose(connection);
            if (connection.getSourceChannel().isReadResumed()) {
                ChannelListeners.invokeChannelListener(connection.getSourceChannel(), connection.getSourceChannel().getReadListener());
            }
            if (connection.getSinkChannel().isWriteResumed()) {
                ChannelListeners.invokeChannelListener(connection.getSinkChannel(), connection.getSinkChannel().getWriteListener());
            }
        }
    };

    public WriteTimeoutStreamSinkConduit(final StreamSinkConduit delegate, StreamConnection connection, OpenListener openListener) {
        super(delegate);
        this.connection = connection;
        this.openListener = openListener;
    }

    private void handleWriteTimeout(final long ret) throws IOException {
        if (!connection.isOpen()) {
            return;
        }
        if (ret == 0 && handle != null) {
            return;
        }
        Integer timeout = getTimeout();
        if (timeout == null || timeout <= 0) {
            return;
        }
        long currentTime = System.currentTimeMillis();
        long expireTimeVar = expireTime;
        if (expireTimeVar != -1 && currentTime > expireTimeVar) {
            IoUtils.safeClose(connection);
            throw new ClosedChannelException();
        }
        expireTime = currentTime + timeout;
    }

    @Override
    public int write(final ByteBuffer src) throws IOException {
        int ret = super.write(src);
        handleWriteTimeout(ret);
        return ret;
    }

    @Override
    public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
        long ret = super.write(srcs, offset, length);
        handleWriteTimeout(ret);
        return ret;
    }

    @Override
    public int writeFinal(ByteBuffer src) throws IOException {
        int ret = super.writeFinal(src);
        handleWriteTimeout(ret);
        if (!src.hasRemaining()) {
            if (handle != null) {
                handle.remove();
                handle = null;
            }
        }
        return ret;
    }

    @Override
    public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
        long ret = super.writeFinal(srcs, offset, length);
        handleWriteTimeout(ret);
        if (!Buffers.hasRemaining(srcs)) {
            if (handle != null) {
                handle.remove();
                handle = null;
            }
        }
        return ret;
    }

    @Override
    public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
        long ret = super.transferFrom(src, position, count);
        handleWriteTimeout(ret);
        return ret;
    }

    @Override
    public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
        long ret = super.transferFrom(source, count, throughBuffer);
        handleWriteTimeout(ret);
        return ret;
    }

    @Override
    public void awaitWritable() throws IOException {
        Integer timeout = getTimeout();
        if (timeout != null && timeout > 0) {
            super.awaitWritable(timeout + FUZZ_FACTOR, TimeUnit.MILLISECONDS);
        } else {
            super.awaitWritable();
        }
    }

    @Override
    public void awaitWritable(long time, TimeUnit timeUnit) throws IOException {
        Integer timeout = getTimeout();
        if (timeout != null && timeout > 0) {
            long millis = timeUnit.toMillis(time);
            super.awaitWritable(Math.min(millis, timeout + FUZZ_FACTOR), TimeUnit.MILLISECONDS);
        } else {
            super.awaitWritable(time, timeUnit);
        }
    }

    private Integer getTimeout() {
        Integer timeout = 0;
        try {
            timeout = connection.getSourceChannel().getOption(Options.WRITE_TIMEOUT);
        } catch (IOException ignore) {
        // should never happen, ignoring
        }
        Integer idleTimeout = openListener.getUndertowOptions().get(UndertowOptions.IDLE_TIMEOUT);
        if ((timeout == null || timeout <= 0) && idleTimeout != null) {
            timeout = idleTimeout;
        } else if (timeout != null && idleTimeout != null && idleTimeout > 0) {
            timeout = Math.min(timeout, idleTimeout);
        }
        return timeout;
    }

    @Override
    public void terminateWrites() throws IOException {
        super.terminateWrites();
        if (handle != null) {
            handle.remove();
            handle = null;
        }
    }

    @Override
    public void truncateWrites() throws IOException {
        super.truncateWrites();
        if (handle != null) {
            handle.remove();
            handle = null;
        }
    }

    @Override
    public void resumeWrites() {
        super.resumeWrites();
        handleResumeTimeout();
    }

    @Override
    public void suspendWrites() {
        super.suspendWrites();
        XnioExecutor.Key handle = this.handle;
        if (handle != null) {
            handle.remove();
            this.handle = null;
        }
    }

    @Override
    public void wakeupWrites() {
        super.wakeupWrites();
        handleResumeTimeout();
    }

    private void handleResumeTimeout() {
        Integer timeout = getTimeout();
        if (timeout == null || timeout <= 0) {
            return;
        }
        long currentTime = System.currentTimeMillis();
        expireTime = currentTime + timeout;
        XnioExecutor.Key key = handle;
        if (key == null) {
            handle = connection.getIoThread().executeAfter(timeoutCommand, timeout, TimeUnit.MILLISECONDS);
        }
    }
}

19 View Complete Implementation : AbstractFramedChannel.java
Copyright Apache License 2.0
Author : undertow-io
protected IdleTimeoutConduit createIdleTimeoutChannel(StreamConnection connectedStreamChannel) {
    return new IdleTimeoutConduit(connectedStreamChannel);
}

19 View Complete Implementation : Hybi13Handshake.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public WebSocketChannel createChannel(WebSocketHttpExchange exchange, final StreamConnection channel, final ByteBufferPool pool) {
    List<ExtensionFunction> extensionFunctions = initExtensions(exchange);
    return new WebSocket13Channel(channel, pool, getWebSocketLocation(exchange), exchange.getResponseHeader(Headers.SEC_WEB_SOCKET_PROTOCOL_STRING), false, !extensionFunctions.isEmpty(), CompositeExtensionFunction.compose(extensionFunctions), exchange.getPeerConnections(), exchange.getOptions());
}

19 View Complete Implementation : JsseSslStreamConnection.java
Copyright Apache License 2.0
Author : xnio
/**
 * StreamConnection with SSL support.
 *
 * @author <a href="mailto:[email protected]">Flavia Rainone</a>
 */
public final clreplaced JsseSslStreamConnection extends SslConnection {

    /**
     * Delegate connection.
     */
    private final StreamConnection connection;

    /**
     * The conduit SSl engine.
     */
    private final JsseSslConduitEngine sslConduitEngine;

    /**
     * Indicates if tls is enabled.
     */
    private volatile boolean tls;

    /**
     * Callback for notification of a handshake being finished.
     */
    private final ChannelListener.SimpleSetter<SslConnection> handshakeSetter = new ChannelListener.SimpleSetter<SslConnection>();

    public JsseSslStreamConnection(StreamConnection connection, SSLEngine sslEngine, final boolean startTls) {
        this(connection, sslEngine, JsseXnioSsl.bufferPool, JsseXnioSsl.bufferPool, startTls);
    }

    JsseSslStreamConnection(StreamConnection connection, SSLEngine sslEngine, final Pool<ByteBuffer> socketBufferPool, final Pool<ByteBuffer> applicationBufferPool, final boolean startTls) {
        super(connection.getIoThread());
        this.connection = connection;
        final StreamSinkConduit sinkConduit = connection.getSinkChannel().getConduit();
        final StreamSourceConduit sourceConduit = connection.getSourceChannel().getConduit();
        sslConduitEngine = new JsseSslConduitEngine(this, sinkConduit, sourceConduit, sslEngine, socketBufferPool, applicationBufferPool);
        tls = !startTls;
        setSinkConduit(new JsseSslStreamSinkConduit(sinkConduit, sslConduitEngine, tls));
        setSourceConduit(new JsseSslStreamSourceConduit(sourceConduit, sslConduitEngine, tls));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized void startHandshake() throws IOException {
        if (!tls) {
            tls = true;
            ((JsseSslStreamSourceConduit) getSourceChannel().getConduit()).enableTls();
            ((JsseSslStreamSinkConduit) getSinkChannel().getConduit()).enableTls();
        }
        sslConduitEngine.beginHandshake();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SocketAddress getPeerAddress() {
        return connection.getPeerAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SocketAddress getLocalAddress() {
        return connection.getLocalAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void closeAction() throws IOException {
        if (tls) {
            try {
                getSinkChannel().getConduit().truncateWrites();
            } catch (IOException e) {
                try {
                    getSourceChannel().getConduit().terminateReads();
                } catch (IOException ignored) {
                }
                safeClose(connection);
                throw e;
            }
            try {
                getSourceChannel().getConduit().terminateReads();
            } catch (IOException e) {
                safeClose(connection);
                throw e;
            }
        }
        connection.close();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void notifyWriteClosed() {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void notifyReadClosed() {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            final SSLEngine engine = sslConduitEngine.getEngine();
            try {
                return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
            } finally {
                engine.setNeedClientAuth(value == SslClientAuthMode.REQUIRED);
                engine.setWantClientAuth(value == SslClientAuthMode.REQUESTED);
            }
        } else if (option == Options.SECURE) {
            throw new IllegalArgumentException();
        } else {
            return connection.setOption(option, value);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> T getOption(final Option<T> option) throws IOException {
        if (option == Options.SSL_CLIENT_AUTH_MODE) {
            final SSLEngine engine = sslConduitEngine.getEngine();
            return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED);
        } else {
            return option == Options.SECURE ? option.cast(Boolean.valueOf(tls)) : connection.getOption(option);
        }
    }

    private static final Set<Option<?>> SUPPORTED_OPTIONS = Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create();

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supportsOption(final Option<?> option) {
        return SUPPORTED_OPTIONS.contains(option) || connection.supportsOption(option);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SSLSession getSslSession() {
        return tls ? sslConduitEngine.getSession() : null;
    }

    @Override
    public org.xnio.ChannelListener.Setter<? extends SslConnection> getHandshakeSetter() {
        return handshakeSetter;
    }

    SSLEngine getEngine() {
        return sslConduitEngine.getEngine();
    }

    protected boolean readClosed() {
        return super.readClosed();
    }

    protected boolean writeClosed() {
        return super.writeClosed();
    }

    /**
     * Callback method for notification of handshake finished.
     */
    protected void handleHandshakeFinished() {
        final ChannelListener<? super SslConnection> listener = handshakeSetter.get();
        if (listener == null) {
            return;
        }
        ChannelListeners.<SslConnection>invokeChannelListener(this, listener);
    }
}

18 View Complete Implementation : HttpClientProvider.java
Copyright Eclipse Public License 1.0
Author : liveoak-io
private void handleConnected(final StreamConnection connection, final ClientCallback<ClientConnection> listener, final Pool<ByteBuffer> bufferPool, final OptionMap options) {
    if (options.get(UndertowOptions.ENABLE_SPDY, false) && connection instanceof SslConnection && SpdyClientProvider.isEnabled()) {
        try {
            SpdyClientProvider.handlePotentialSpdyConnection(connection, listener, bufferPool, options, new ChannelListener<SslConnection>() {

                @Override
                public void handleEvent(SslConnection channel) {
                    listener.completed(new HttpClientConnection(connection, options, bufferPool));
                }
            });
        } catch (Exception e) {
            listener.failed(new IOException(e));
        }
    } else {
        listener.completed(new HttpClientConnection(connection, options, bufferPool));
    }
}

18 View Complete Implementation : UndertowAcceptingSslChannel.java
Copyright Apache License 2.0
Author : undertow-io
protected UndertowSslConnection accept(StreamConnection tcpServer, SSLEngine sslEngine) throws IOException {
    return new UndertowSslConnection(tcpServer, sslEngine, applicationBufferPool);
}

18 View Complete Implementation : UndertowXnioSsl.java
Copyright Apache License 2.0
Author : undertow-io
public SslConnection wrapExistingConnection(StreamConnection connection, OptionMap optionMap, boolean clientMode) {
    return new UndertowSslConnection(connection, createSSLEngine(sslContext, optionMap, (InetSocketAddress) connection.getPeerAddress(), clientMode), bufferPool);
}

18 View Complete Implementation : UndertowXnioSsl.java
Copyright Apache License 2.0
Author : undertow-io
public SslConnection wrapExistingConnection(StreamConnection connection, OptionMap optionMap) {
    return new UndertowSslConnection(connection, createSSLEngine(sslContext, optionMap, (InetSocketAddress) connection.getPeerAddress(), true), bufferPool);
}

18 View Complete Implementation : HttpReadListener.java
Copyright Apache License 2.0
Author : undertow-io
private void sendBadRequestAndClose(final StreamConnection connection, final Throwable exception) {
    UndertowLogger.REQUEST_IO_LOGGER.failedToParseRequest(exception);
    connection.getSourceChannel().suspendReads();
    new StringWriteChannelListener(BAD_REQUEST) {

        @Override
        protected void writeDone(final StreamSinkChannel c) {
            super.writeDone(c);
            c.suspendWrites();
            IoUtils.safeClose(connection);
        }

        @Override
        protected void handleError(StreamSinkChannel channel, IOException e) {
            IoUtils.safeClose(connection);
        }
    }.setup(connection.getSinkChannel());
}

18 View Complete Implementation : ProxyProtocolReadListener.java
Copyright Apache License 2.0
Author : undertow-io
private void callOpenListener(StreamConnection streamConnection, final PooledByteBuffer buffer) {
    if (openListener instanceof DelegateOpenListener) {
        ((DelegateOpenListener) openListener).handleEvent(streamConnection, buffer);
    } else {
        if (buffer != null) {
            PushBackStreamSourceConduit conduit = new PushBackStreamSourceConduit(streamConnection.getSourceChannel().getConduit());
            conduit.pushBack(new PooledAdaptor(buffer));
            streamConnection.getSourceChannel().setConduit(conduit);
        }
        openListener.handleEvent(streamConnection);
    }
}

18 View Complete Implementation : ProxyProtocolReadListener.java
Copyright Apache License 2.0
Author : undertow-io
/**
 * Implementation of version 1 and 2 of the proxy protocol (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
 * <p>
 * Even though it is not required by the spec this implementation provides a stateful parser, that can handle
 * fragmentation of
 *
 * @author Stuart Douglas
 * @author Ulrich Herberg
 */
clreplaced ProxyProtocolReadListener implements ChannelListener<StreamSourceChannel> {

    private static final int MAX_HEADER_LENGTH = 107;

    private static final byte[] NAME = "PROXY ".getBytes(StandardCharsets.US_ASCII);

    private static final String UNKNOWN = "UNKNOWN";

    private static final String TCP4 = "TCP4";

    private static final String TCP6 = "TCP6";

    private static final byte[] SIG = new byte[] { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };

    private final StreamConnection streamConnection;

    private final OpenListener openListener;

    private final UndertowXnioSsl ssl;

    private final ByteBufferPool bufferPool;

    private final OptionMap sslOptionMap;

    private int byteCount;

    private String protocol;

    private InetAddress sourceAddress;

    private InetAddress destAddress;

    private int sourcePort = -1;

    private int destPort = -1;

    private StringBuilder stringBuilder = new StringBuilder();

    private boolean carriageReturnSeen = false;

    private boolean parsingUnknown = false;

    ProxyProtocolReadListener(StreamConnection streamConnection, OpenListener openListener, UndertowXnioSsl ssl, ByteBufferPool bufferPool, OptionMap sslOptionMap) {
        this.streamConnection = streamConnection;
        this.openListener = openListener;
        this.ssl = ssl;
        this.bufferPool = bufferPool;
        this.sslOptionMap = sslOptionMap;
        if (bufferPool.getBufferSize() < MAX_HEADER_LENGTH) {
            throw UndertowMessages.MESSAGES.bufferPoolTooSmall(MAX_HEADER_LENGTH);
        }
    }

    @Override
    public void handleEvent(StreamSourceChannel streamSourceChannel) {
        PooledByteBuffer buffer = bufferPool.allocate();
        AtomicBoolean freeBuffer = new AtomicBoolean(true);
        try {
            int res = streamSourceChannel.read(buffer.getBuffer());
            if (res == -1) {
                IoUtils.safeClose(streamConnection);
                return;
            } else if (res == 0) {
                return;
            } else {
                buffer.getBuffer().flip();
                if (buffer.getBuffer().hasRemaining()) {
                    // get first byte to determine whether Proxy Protocol V1 or V2 is used
                    byte firstByte = buffer.getBuffer().get();
                    byteCount++;
                    if (firstByte == SIG[0]) {
                        // Could be Proxy Protocol V2
                        parseProxyProtocolV2(buffer, freeBuffer);
                    } else if ((char) firstByte == NAME[0]) {
                        // Could be Proxy Protocol V1
                        parseProxyProtocolV1(buffer, freeBuffer);
                    } else {
                        throw UndertowMessages.MESSAGES.invalidProxyHeader();
                    }
                }
                return;
            }
        } catch (IOException e) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
            IoUtils.safeClose(streamConnection);
        } catch (Exception e) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(new IOException(e));
            IoUtils.safeClose(streamConnection);
        } finally {
            if (freeBuffer.get()) {
                buffer.close();
            }
        }
    }

    private void parseProxyProtocolV2(PooledByteBuffer buffer, AtomicBoolean freeBuffer) throws Exception {
        while (byteCount < SIG.length) {
            byte c = buffer.getBuffer().get();
            // first we verify that we have the correct protocol
            if (c != SIG[byteCount]) {
                throw UndertowMessages.MESSAGES.invalidProxyHeader();
            }
            byteCount++;
        }
        byte ver_cmd = buffer.getBuffer().get();
        byte fam = buffer.getBuffer().get();
        int len = (buffer.getBuffer().getShort() & 0xffff);
        if ((ver_cmd & 0xF0) != 0x20) {
            // expect version 2
            throw UndertowMessages.MESSAGES.invalidProxyHeader();
        }
        switch(ver_cmd & 0x0F) {
            case // PROXY command
            0x01:
                switch(fam) {
                    case 0x11:
                        {
                            // TCP over IPv4
                            if (len < 12) {
                                throw UndertowMessages.MESSAGES.invalidProxyHeader();
                            }
                            byte[] sourceAddressBytes = new byte[4];
                            buffer.getBuffer().get(sourceAddressBytes);
                            sourceAddress = InetAddress.getByAddress(sourceAddressBytes);
                            byte[] dstAddressBytes = new byte[4];
                            buffer.getBuffer().get(dstAddressBytes);
                            destAddress = InetAddress.getByAddress(dstAddressBytes);
                            sourcePort = buffer.getBuffer().getShort() & 0xffff;
                            destPort = buffer.getBuffer().getShort() & 0xffff;
                            if (len > 12) {
                                int skipAhead = len - 12;
                                int currentPosition = buffer.getBuffer().position();
                                buffer.getBuffer().position(currentPosition + skipAhead);
                            }
                            break;
                        }
                    case 0x21:
                        {
                            // TCP over IPv6
                            if (len < 36) {
                                throw UndertowMessages.MESSAGES.invalidProxyHeader();
                            }
                            byte[] sourceAddressBytes = new byte[16];
                            buffer.getBuffer().get(sourceAddressBytes);
                            sourceAddress = InetAddress.getByAddress(sourceAddressBytes);
                            byte[] dstAddressBytes = new byte[16];
                            buffer.getBuffer().get(dstAddressBytes);
                            destAddress = InetAddress.getByAddress(dstAddressBytes);
                            sourcePort = buffer.getBuffer().getShort() & 0xffff;
                            destPort = buffer.getBuffer().getShort() & 0xffff;
                            if (len > 36) {
                                int skipAhead = len - 36;
                                int currentPosition = buffer.getBuffer().position();
                                buffer.getBuffer().position(currentPosition + skipAhead);
                            }
                            break;
                        }
                    default:
                        // AF_UNIX sockets not supported
                        throw UndertowMessages.MESSAGES.invalidProxyHeader();
                }
                break;
            case // LOCAL command
            0x00:
                if (len > 0) {
                    int skipAhead = len;
                    int currentPosition = buffer.getBuffer().position();
                    buffer.getBuffer().position(currentPosition + skipAhead);
                }
                if (buffer.getBuffer().hasRemaining()) {
                    freeBuffer.set(false);
                    proxyAccept(null, null, buffer);
                } else {
                    proxyAccept(null, null, null);
                }
                return;
            default:
                throw UndertowMessages.MESSAGES.invalidProxyHeader();
        }
        SocketAddress s = new InetSocketAddress(sourceAddress, sourcePort);
        SocketAddress d = new InetSocketAddress(destAddress, destPort);
        if (buffer.getBuffer().hasRemaining()) {
            freeBuffer.set(false);
            proxyAccept(s, d, buffer);
        } else {
            proxyAccept(s, d, null);
        }
        return;
    }

    private void parseProxyProtocolV1(PooledByteBuffer buffer, AtomicBoolean freeBuffer) throws Exception {
        while (buffer.getBuffer().hasRemaining()) {
            char c = (char) buffer.getBuffer().get();
            if (byteCount < NAME.length) {
                // first we verify that we have the correct protocol
                if (c != NAME[byteCount]) {
                    throw UndertowMessages.MESSAGES.invalidProxyHeader();
                }
            } else {
                if (parsingUnknown) {
                    // we are parsing the UNKNOWN protocol
                    // we just ignore everything till \r\n
                    if (c == '\r') {
                        carriageReturnSeen = true;
                    } else if (c == '\n') {
                        if (!carriageReturnSeen) {
                            throw UndertowMessages.MESSAGES.invalidProxyHeader();
                        }
                        // we are done
                        if (buffer.getBuffer().hasRemaining()) {
                            freeBuffer.set(false);
                            proxyAccept(null, null, buffer);
                        } else {
                            proxyAccept(null, null, null);
                        }
                        return;
                    } else if (carriageReturnSeen) {
                        throw UndertowMessages.MESSAGES.invalidProxyHeader();
                    }
                } else if (carriageReturnSeen) {
                    if (c == '\n') {
                        // we are done
                        SocketAddress s = new InetSocketAddress(sourceAddress, sourcePort);
                        SocketAddress d = new InetSocketAddress(destAddress, destPort);
                        if (buffer.getBuffer().hasRemaining()) {
                            freeBuffer.set(false);
                            proxyAccept(s, d, buffer);
                        } else {
                            proxyAccept(s, d, null);
                        }
                        return;
                    } else {
                        throw UndertowMessages.MESSAGES.invalidProxyHeader();
                    }
                } else
                    switch(c) {
                        case ' ':
                            // we have a space
                            if (sourcePort != -1 || stringBuilder.length() == 0) {
                                // header was invalid, either we are expecting a \r or a \n, or the previous character was a space
                                throw UndertowMessages.MESSAGES.invalidProxyHeader();
                            } else if (protocol == null) {
                                protocol = stringBuilder.toString();
                                stringBuilder.setLength(0);
                                if (protocol.equals(UNKNOWN)) {
                                    parsingUnknown = true;
                                } else if (!protocol.equals(TCP4) && !protocol.equals(TCP6)) {
                                    throw UndertowMessages.MESSAGES.invalidProxyHeader();
                                }
                            } else if (sourceAddress == null) {
                                sourceAddress = parseAddress(stringBuilder.toString(), protocol);
                                stringBuilder.setLength(0);
                            } else if (destAddress == null) {
                                destAddress = parseAddress(stringBuilder.toString(), protocol);
                                stringBuilder.setLength(0);
                            } else {
                                sourcePort = Integer.parseInt(stringBuilder.toString());
                                stringBuilder.setLength(0);
                            }
                            break;
                        case '\r':
                            if (destPort == -1 && sourcePort != -1 && !carriageReturnSeen && stringBuilder.length() > 0) {
                                destPort = Integer.parseInt(stringBuilder.toString());
                                stringBuilder.setLength(0);
                                carriageReturnSeen = true;
                            } else if (protocol == null) {
                                if (UNKNOWN.equals(stringBuilder.toString())) {
                                    parsingUnknown = true;
                                    carriageReturnSeen = true;
                                }
                            } else {
                                throw UndertowMessages.MESSAGES.invalidProxyHeader();
                            }
                            break;
                        case '\n':
                            throw UndertowMessages.MESSAGES.invalidProxyHeader();
                        default:
                            stringBuilder.append(c);
                    }
            }
            byteCount++;
            if (byteCount == MAX_HEADER_LENGTH) {
                throw UndertowMessages.MESSAGES.headerSizeToLarge();
            }
        }
    }

    private void proxyAccept(SocketAddress source, SocketAddress dest, PooledByteBuffer additionalData) {
        StreamConnection streamConnection = this.streamConnection;
        if (source != null) {
            streamConnection = new AddressWrappedConnection(streamConnection, source, dest);
        }
        if (ssl != null) {
            // we need to apply the additional data before the SSL wrapping
            if (additionalData != null) {
                PushBackStreamSourceConduit conduit = new PushBackStreamSourceConduit(streamConnection.getSourceChannel().getConduit());
                conduit.pushBack(new PooledAdaptor(additionalData));
                streamConnection.getSourceChannel().setConduit(conduit);
            }
            SslConnection sslConnection = ssl.wrapExistingConnection(streamConnection, sslOptionMap == null ? OptionMap.EMPTY : sslOptionMap, false);
            streamConnection = sslConnection;
            callOpenListener(streamConnection, null);
        } else {
            callOpenListener(streamConnection, additionalData);
        }
    }

    private void callOpenListener(StreamConnection streamConnection, final PooledByteBuffer buffer) {
        if (openListener instanceof DelegateOpenListener) {
            ((DelegateOpenListener) openListener).handleEvent(streamConnection, buffer);
        } else {
            if (buffer != null) {
                PushBackStreamSourceConduit conduit = new PushBackStreamSourceConduit(streamConnection.getSourceChannel().getConduit());
                conduit.pushBack(new PooledAdaptor(buffer));
                streamConnection.getSourceChannel().setConduit(conduit);
            }
            openListener.handleEvent(streamConnection);
        }
    }

    static InetAddress parseAddress(String addressString, String protocol) throws IOException {
        if (protocol.equals(TCP4)) {
            return NetworkUtils.parseIpv4Address(addressString);
        } else {
            return NetworkUtils.parseIpv6Address(addressString);
        }
    }

    private static final clreplaced AddressWrappedConnection extends StreamConnection {

        private final StreamConnection delegate;

        private final SocketAddress source;

        private final SocketAddress dest;

        AddressWrappedConnection(StreamConnection delegate, SocketAddress source, SocketAddress dest) {
            super(delegate.getIoThread());
            this.delegate = delegate;
            this.source = source;
            this.dest = dest;
            setSinkConduit(delegate.getSinkChannel().getConduit());
            setSourceConduit(delegate.getSourceChannel().getConduit());
        }

        @Override
        protected void notifyWriteClosed() {
            IoUtils.safeClose(delegate.getSinkChannel());
        }

        @Override
        protected void notifyReadClosed() {
            IoUtils.safeClose(delegate.getSourceChannel());
        }

        @Override
        public SocketAddress getPeerAddress() {
            return source;
        }

        @Override
        public SocketAddress getLocalAddress() {
            return dest;
        }
    }
}

18 View Complete Implementation : WebSocket13ClientHandshake.java
Copyright Apache License 2.0
Author : undertow-io
@Override
public WebSocketChannel createChannel(final StreamConnection channel, final String wsUri, final ByteBufferPool bufferPool, OptionMap options) {
    if (negotiation != null && negotiation.getSelectedExtensions() != null && !negotiation.getSelectedExtensions().isEmpty()) {
        List<WebSocketExtension> selected = negotiation.getSelectedExtensions();
        List<ExtensionFunction> negotiated = new ArrayList<>();
        if (selected != null && !selected.isEmpty()) {
            for (WebSocketExtension ext : selected) {
                for (ExtensionHandshake extHandshake : extensions) {
                    if (ext.getName().equals(extHandshake.getName())) {
                        negotiated.add(extHandshake.create());
                    }
                }
            }
        }
        return new WebSocket13Channel(channel, bufferPool, wsUri, negotiation.getSelectedSubProtocol(), true, !negotiated.isEmpty(), CompositeExtensionFunction.compose(negotiated), new HashSet<WebSocketChannel>(), options);
    } else {
        return new WebSocket13Channel(channel, bufferPool, wsUri, negotiation != null ? negotiation.getSelectedSubProtocol() : "", true, false, NoopExtensionFunction.INSTANCE, new HashSet<WebSocketChannel>(), options);
    }
}

18 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
private static void suspend(StreamConnection connection) {
    if (connection == null) {
        return;
    }
    connection.getSourceChannel().suspendReads();
    connection.getSinkChannel().suspendWrites();
}

18 View Complete Implementation : AbstractXnioSocketChannel.java
Copyright Apache License 2.0
Author : xnio
@Override
protected SocketAddress localAddress0() {
    StreamConnection conn = connection();
    if (conn == null) {
        return null;
    }
    return conn.getLocalAddress();
}

18 View Complete Implementation : ConduitMock.java
Copyright Apache License 2.0
Author : xnio
@Override
public long transferTo(long position, long count, FileChannel target) throws IOException {
    if (readsEnabled) {
        final StreamConnection connection = new StreamConnectionMock(this);
        final replacedembledConnectedStreamChannel replacedembledChannel = new replacedembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel());
        return target.transferFrom(replacedembledChannel, position, count);
    }
    return 0;
}

17 View Complete Implementation : HttpReadListener.java
Copyright Apache License 2.0
Author : undertow-io
private void handleHttp2PriorKnowledge(final StreamConnection connection, final HttpServerConnection serverConnection, PooledByteBuffer readData) throws IOException {
    final ConduitStreamSourceChannel request = connection.getSourceChannel();
    byte[] data = new byte[PRI_EXPECTED.length];
    final ByteBuffer buffer = ByteBuffer.wrap(data);
    if (readData.getBuffer().hasRemaining()) {
        while (readData.getBuffer().hasRemaining() && buffer.hasRemaining()) {
            buffer.put(readData.getBuffer().get());
        }
    }
    final PooledByteBuffer extraData;
    if (readData.getBuffer().hasRemaining()) {
        extraData = readData;
    } else {
        readData.close();
        extraData = null;
    }
    if (!doHttp2PriRead(connection, buffer, serverConnection, extraData)) {
        request.getReadSetter().set(new ChannelListener<StreamSourceChannel>() {

            @Override
            public void handleEvent(StreamSourceChannel channel) {
                try {
                    doHttp2PriRead(connection, buffer, serverConnection, extraData);
                } catch (IOException e) {
                    UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
                    IoUtils.safeClose(connection);
                } catch (Throwable t) {
                    UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t);
                    IoUtils.safeClose(connection);
                }
            }
        });
        request.resumeReads();
    }
}

17 View Complete Implementation : PipeliningBufferingStreamSinkConduit.java
Copyright Apache License 2.0
Author : undertow-io
void performFlush(final HttpServerExchange exchange, final HttpServerConnection connection) {
    try {
        final HttpServerConnection.ConduitState oldState = connection.resetChannel();
        if (!flushPipelinedData()) {
            final StreamConnection channel = connection.getChannel();
            channel.getSinkChannel().setWriteListener(new ChannelListener<Channel>() {

                @Override
                public void handleEvent(Channel c) {
                    try {
                        if (flushPipelinedData()) {
                            channel.getSinkChannel().setWriteListener(null);
                            channel.getSinkChannel().suspendWrites();
                            connection.restoreChannel(oldState);
                            connection.getReadListener().exchangeComplete(exchange);
                        }
                    } catch (IOException e) {
                        UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
                        IoUtils.safeClose(channel);
                    } catch (Throwable t) {
                        UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t);
                        IoUtils.safeClose(channel);
                    }
                }
            });
            connection.getChannel().getSinkChannel().resumeWrites();
            return;
        } else {
            connection.restoreChannel(oldState);
            connection.getReadListener().exchangeComplete(exchange);
        }
    } catch (IOException e) {
        UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
        IoUtils.safeClose(connection.getChannel());
    } catch (Throwable t) {
        UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t);
        IoUtils.safeClose(connection.getChannel());
    }
}