private void flush0( final ChannelHandlerContext ctx, final int bytesConsumed, final Throwable cause) { ChannelFuture flushFuture = ctx.flush( ctx.newFuture() .addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (ctx.executor() == ctx.channel().eventLoop()) { notifyFlushFutures(bytesConsumed, cause, future); } else { synchronized (flushFutureNotifier) { notifyFlushFutures(bytesConsumed, cause, future); } } } private void notifyFlushFutures( int bytesConsumed, Throwable cause, ChannelFuture future) { flushFutureNotifier.increaseWriteCounter(bytesConsumed); if (future.isSuccess()) { flushFutureNotifier.notifyFlushFutures(cause); } else { flushFutureNotifier.notifyFlushFutures(cause, future.cause()); } } })); safeClose(ctx, flushFuture, ctx.newFuture()); }
private void closeOutboundAndChannel( final ChannelHandlerContext ctx, final ChannelFuture future, boolean disconnect) throws Exception { if (!ctx.channel().isActive()) { if (disconnect) { ctx.disconnect(future); } else { ctx.close(future); } return; } engine.closeOutbound(); ChannelFuture closeNotifyFuture = ctx.newFuture(); flush(ctx, closeNotifyFuture); safeClose(ctx, closeNotifyFuture, future); }
@Override public void inboundBufferUpdated(final ChannelHandlerContext ctx) throws Exception { final ByteBuf in = ctx.inboundByteBuffer(); if (in.readableBytes() < 5) { return; } int packetLength = getEncryptedPacketLength(in); if (packetLength == -1) { // Bad data - discard the buffer and raise an exception. NotSslRecordException e = new NotSslRecordException("not an SSL/TLS record: " + ByteBufUtil.hexDump(in)); in.skipBytes(in.readableBytes()); ctx.fireExceptionCaught(e); setHandshakeFailure(e); return; } assert packetLength > 0; final ByteBuf out = ctx.nextInboundByteBuffer(); out.discardReadBytes(); boolean wrapLater = false; int bytesProduced = 0; try { loop: for (; ; ) { SSLEngineResult result = unwrap(engine, in, out); bytesProduced += result.bytesProduced(); switch (result.getStatus()) { case CLOSED: // notify about the CLOSED state of the SSLEngine. See #137 sslCloseFuture.setClosed(); break; case BUFFER_UNDERFLOW: break loop; } switch (result.getHandshakeStatus()) { case NEED_UNWRAP: break; case NEED_WRAP: wrapLater = true; break; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: setHandshakeSuccess(); wrapLater = true; continue; case NOT_HANDSHAKING: break; default: throw new IllegalStateException( "Unknown handshake status: " + result.getHandshakeStatus()); } if (result.bytesConsumed() == 0 && result.bytesProduced() == 0) { break; } } if (wrapLater) { flush(ctx, ctx.newFuture()); } } catch (SSLException e) { setHandshakeFailure(e); throw e; } finally { if (bytesProduced > 0) { in.discardReadBytes(); ctx.fireInboundBufferUpdated(); } } }
/** * Sends an SSL {@code close_notify} message to the specified channel and destroys the underlying * {@link SSLEngine}. */ public ChannelFuture close() { return close(ctx.newFuture()); }
/** * Starts the SSL / TLS handshake and returns a {@link ChannelFuture} that will get notified once * the handshake completes. */ public ChannelFuture handshake() { return handshake(ctx.newFuture()); }