private ChannelFuture wrap(ChannelHandlerContext context, Channel channel) throws SSLException { ChannelFuture future = null; ChannelBuffer msg; ByteBuffer outNetBuf = bufferPool.acquire(); boolean success = true; boolean offered = false; boolean needsUnwrap = false; try { loop: for (; ; ) { // Acquire a lock to make sure unencrypted data is polled // in order and their encrypted counterpart is offered in // order. synchronized (pendingUnencryptedWrites) { PendingWrite pendingWrite = pendingUnencryptedWrites.peek(); if (pendingWrite == null) { break; } ByteBuffer outAppBuf = pendingWrite.outAppBuf; if (outAppBuf == null) { // A write request with an empty buffer pendingUnencryptedWrites.remove(); offerEncryptedWriteRequest( new DownstreamMessageEvent( channel, pendingWrite.future, ChannelBuffers.EMPTY_BUFFER, channel.getRemoteAddress())); offered = true; } else { SSLEngineResult result = null; try { synchronized (handshakeLock) { result = engine.wrap(outAppBuf, outNetBuf); } } finally { if (!outAppBuf.hasRemaining()) { pendingUnencryptedWrites.remove(); } } if (result.bytesProduced() > 0) { outNetBuf.flip(); msg = ChannelBuffers.buffer(outNetBuf.remaining()); msg.writeBytes(outNetBuf.array(), 0, msg.capacity()); outNetBuf.clear(); if (pendingWrite.outAppBuf.hasRemaining()) { // pendingWrite's future shouldn't be notified if // only partial data is written. future = succeededFuture(channel); } else { future = pendingWrite.future; } MessageEvent encryptedWrite = new DownstreamMessageEvent(channel, future, msg, channel.getRemoteAddress()); offerEncryptedWriteRequest(encryptedWrite); offered = true; } else { final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case NEED_WRAP: if (outAppBuf.hasRemaining()) { break; } else { break loop; } case NEED_UNWRAP: needsUnwrap = true; break loop; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: case NOT_HANDSHAKING: if (handshakeStatus == HandshakeStatus.FINISHED) { setHandshakeSuccess(channel); } if (result.getStatus() == Status.CLOSED) { success = false; } break loop; default: throw new IllegalStateException("Unknown handshake status: " + handshakeStatus); } } } } } } catch (SSLException e) { success = false; setHandshakeFailure(channel, e); throw e; } finally { bufferPool.release(outNetBuf); if (offered) { flushPendingEncryptedWrites(context); } if (!success) { IllegalStateException cause = new IllegalStateException("SSLEngine already closed"); // Mark all remaining pending writes as failure if anything // wrong happened before the write requests are wrapped. // Please note that we do not call setFailure while a lock is // acquired, to avoid a potential dead lock. for (; ; ) { PendingWrite pendingWrite; synchronized (pendingUnencryptedWrites) { pendingWrite = pendingUnencryptedWrites.poll(); if (pendingWrite == null) { break; } } pendingWrite.future.setFailure(cause); } } } if (needsUnwrap) { unwrap(context, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0); } if (future == null) { future = succeededFuture(channel); } return future; }