/** * Starts an SSL / TLS handshake for the specified channel. * * @return a {@link ChannelFuture} which is notified when the handshake succeeds or fails. */ public ChannelFuture handshake() { if (handshaken && !isEnableRenegotiation()) { throw new IllegalStateException("renegotiation disabled"); } ChannelHandlerContext ctx = this.ctx; Channel channel = ctx.getChannel(); ChannelFuture handshakeFuture; synchronized (handshakeLock) { if (handshaking) { return this.handshakeFuture; } else { handshaking = true; try { engine.beginHandshake(); runDelegatedTasks(); handshakeFuture = this.handshakeFuture = future(channel); } catch (SSLException e) { handshakeFuture = this.handshakeFuture = failedFuture(channel, e); } } } try { wrapNonAppData(ctx, channel); } catch (SSLException e) { handshakeFuture.setFailure(e); } return handshakeFuture; }
private ChannelBuffer unwrap( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length) throws SSLException { ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length); ByteBuffer outAppBuf = bufferPool.acquire(); try { boolean needsWrap = false; loop: for (; ; ) { SSLEngineResult result; synchronized (handshakeLock) { if (!handshaken && !handshaking && !engine.getUseClientMode() && !engine.isInboundDone() && !engine.isOutboundDone()) { handshake(); } try { result = engine.unwrap(inNetBuf, outAppBuf); } catch (SSLException e) { throw e; } final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case NEED_UNWRAP: if (inNetBuf.hasRemaining() && !engine.isInboundDone()) { break; } else { break loop; } case NEED_WRAP: wrapNonAppData(ctx, channel); break; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: setHandshakeSuccess(channel); needsWrap = true; break loop; case NOT_HANDSHAKING: needsWrap = true; break loop; default: throw new IllegalStateException("Unknown handshake status: " + handshakeStatus); } } } if (needsWrap) { // wrap() acquires pendingUnencryptedWrites first and then // handshakeLock. If handshakeLock is already hold by the // current thread, calling wrap() will lead to a dead lock // i.e. pendingUnencryptedWrites -> handshakeLock vs. // handshakeLock -> pendingUnencryptedLock -> handshakeLock // // There is also a same issue between pendingEncryptedWrites // and pendingUnencryptedWrites. if (!Thread.holdsLock(handshakeLock) && !pendingEncryptedWritesLock.isHeldByCurrentThread()) { wrap(ctx, channel); } } outAppBuf.flip(); if (outAppBuf.hasRemaining()) { ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining()); frame.writeBytes(outAppBuf.array(), 0, frame.capacity()); return frame; } else { return null; } } catch (SSLException e) { setHandshakeFailure(channel, e); throw e; } finally { bufferPool.release(outAppBuf); } }