private void setCallbacks() {
        mProxyTunnel.setNioCallback(new NioCallback() {
            @Override
            public void onConnected() {
                // Nothing to do.
            }

            @Override
            public void onRead() throws IOException {
                if (mProxyTunnel.isClosed()) {
                    mGateway.onResponseFinished();
                    return;
                }
                ByteBuffer buffer = ByteBuffer.allocate(mMtu);
                int len;
                try {
                    len = mProxyTunnel.read(buffer);
                } catch (IOException e) {
                    throw new ConnectionShutdownException(e.getMessage());
                }
                if (len < 0 || mRemoteTunnel.isClosed()) {
                    NetBareUtils.closeQuietly(mProxyTunnel);
                    mGateway.onResponseFinished();
                    return;
                }
                mGateway.onRequest(buffer);
            }

            @Override
            public void onWrite() {
                // Do nothing
            }

            @Override
            public void onClosed() {
                close();
            }

            @Override
            public NioTunnel getTunnel() {
                return null;
            }
        });
        mRemoteTunnel.setNioCallback(new NioCallback() {
            @Override
            public void onConnected() throws IOException {
                // Prepare to read data.
                mProxyTunnel.prepareRead();
                mRemoteTunnel.prepareRead();
            }

            @Override
            public void onRead() throws IOException {
                if (mRemoteTunnel.isClosed()) {
                    mGateway.onRequestFinished();
                    return;
                }
                ByteBuffer buffer = ByteBuffer.allocate(mMtu);
                int len;
                try {
                    len = mRemoteTunnel.read(buffer);
                } catch (IOException e) {
                    throw new ConnectionShutdownException(e.getMessage());
                }
                if (len < 0 || mProxyTunnel.isClosed()) {
                    NetBareUtils.closeQuietly(mRemoteTunnel);
                    mGateway.onRequestFinished();
                    return;
                }
                mGateway.onResponse(buffer);
            }

            @Override
            public void onWrite() {
                // Do nothing
            }

            @Override
            public void onClosed() {
                close();
            }

            @Override
            public NioTunnel getTunnel() {
                return null;
            }

        });
    }
TCP protocol virtual gateway tunnel wraps {@link TcpProxyTunnel} and {@link TcpRemoteTunnel} as
client and server.

@author Megatron King
@since 2018-11-18 00:19
netbare-core/src/main/java/com/github/megatronking/netbare/tunnel/TcpVATunnel.java