2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.io.ssl;
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.nio.channels.ClosedChannelException;
24 import java.util.Arrays;
25 import java.util.concurrent.Executor;
27 import javax.net.ssl.SSLEngine;
28 import javax.net.ssl.SSLEngineResult;
29 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
30 import javax.net.ssl.SSLEngineResult.Status;
31 import javax.net.ssl.SSLException;
33 import org.eclipse.jetty.io.AbstractConnection;
34 import org.eclipse.jetty.io.AbstractEndPoint;
35 import org.eclipse.jetty.io.ByteBufferPool;
36 import org.eclipse.jetty.io.Connection;
37 import org.eclipse.jetty.io.EndPoint;
38 import org.eclipse.jetty.io.EofException;
39 import org.eclipse.jetty.io.FillInterest;
40 import org.eclipse.jetty.io.RuntimeIOException;
41 import org.eclipse.jetty.io.SelectChannelEndPoint;
42 import org.eclipse.jetty.io.WriteFlusher;
43 import org.eclipse.jetty.util.BufferUtil;
44 import org.eclipse.jetty.util.Callback;
45 import org.eclipse.jetty.util.log.Log;
46 import org.eclipse.jetty.util.log.Logger;
49 * A Connection that acts as an interceptor between an EndPoint providing SSL encrypted data
50 * and another consumer of an EndPoint (typically an {@link Connection} like HttpConnection) that
51 * wants unencrypted data.
53 * The connector uses an {@link EndPoint} (typically {@link SelectChannelEndPoint}) as
54 * it's source/sink of encrypted data. It then provides an endpoint via {@link #getDecryptedEndPoint()} to
55 * expose a source/sink of unencrypted data to another connection (eg HttpConnection).
57 * The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any
58 * asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
60 * The passive methods are {@link DecryptedEndPoint#fill(ByteBuffer)} and {@link DecryptedEndPoint#flush(ByteBuffer...)}. They make best
61 * effort attempts to progress the connection using only calls to the encrypted {@link EndPoint#fill(ByteBuffer)} and {@link EndPoint#flush(ByteBuffer...)}
62 * methods. They will never block nor schedule any readInterest or write callbacks. If a fill/flush cannot progress either because
63 * of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
64 * Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
65 * encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Callback)}.
67 * It is only the active methods : {@link DecryptedEndPoint#fillInterested(Callback)} and
68 * {@link DecryptedEndPoint#write(Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
69 * {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Callback, ByteBuffer...)}
70 * methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
71 * write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
72 * to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
74 * MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing
75 * themselves. Instead they simple make the callbacks to the decrypted callbacks, so that the passive encrypted fill/flush will
76 * be called again and make another best effort attempt to progress the connection.
79 public class SslConnection extends AbstractConnection
81 private static final Logger LOG = Log.getLogger(SslConnection.class);
82 private static final boolean DEBUG = LOG.isDebugEnabled(); // Easy for the compiler to remove the code if DEBUG==false
83 private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0);
84 private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0);
85 private final ByteBufferPool _bufferPool;
86 private SSLEngine _sslEngine;
87 private final SslReconfigurator _sslFactory;
88 private final DecryptedEndPoint _decryptedEndPoint;
89 private ByteBuffer _decryptedInput;
90 private ByteBuffer _encryptedInput;
91 private ByteBuffer _encryptedOutput;
92 private final boolean _encryptedDirectBuffers = false;
93 private final boolean _decryptedDirectBuffers = false;
94 private final Runnable _runCompletWrite = new Runnable()
99 _decryptedEndPoint.getWriteFlusher().completeWrite();
102 private boolean _renegotiationAllowed;
104 public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine)
106 this(byteBufferPool, executor, endPoint, sslEngine, null);
108 public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine, SslReconfigurator fact)
110 // This connection does not execute calls to onfillable, so they will be called by the selector thread.
111 // onfillable does not block and will only wakeup another thread to do the actual reading and handling.
112 super(endPoint, executor, !EXECUTE_ONFILLABLE);
113 this._bufferPool = byteBufferPool;
114 this._sslEngine = sslEngine;
115 this._sslFactory = fact;
116 this._decryptedEndPoint = newDecryptedEndPoint();
119 protected DecryptedEndPoint newDecryptedEndPoint()
121 return new DecryptedEndPoint();
124 public SSLEngine getSSLEngine()
129 public DecryptedEndPoint getDecryptedEndPoint()
131 return _decryptedEndPoint;
134 public boolean isRenegotiationAllowed()
136 return _renegotiationAllowed;
139 public void setRenegotiationAllowed(boolean renegotiationAllowed)
141 this._renegotiationAllowed = renegotiationAllowed;
149 // Begin the handshake
150 _sslEngine.beginHandshake();
152 getDecryptedEndPoint().getConnection().onOpen();
154 catch (SSLException x)
156 getEndPoint().close();
157 throw new RuntimeIOException(x);
162 public void onClose()
164 _decryptedEndPoint.getConnection().onClose();
171 getDecryptedEndPoint().getConnection().close();
175 public void onFillable()
177 // onFillable means that there are encrypted bytes ready to be filled.
178 // however we do not fill them here on this callback, but instead wakeup
179 // the decrypted readInterest and/or writeFlusher so that they will attempt
180 // to do the fill and/or flush again and these calls will do the actually
184 LOG.debug("onFillable enter {}", _decryptedEndPoint);
186 // We have received a close handshake, close the end point to send FIN.
187 if (_decryptedEndPoint.isInputShutdown())
188 _decryptedEndPoint.close();
190 // wake up whoever is doing the fill or the flush so they can
191 // do all the filling, unwrapping, wrapping and flushing
192 _decryptedEndPoint.getFillInterest().fillable();
194 // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
195 synchronized(_decryptedEndPoint)
197 if (_decryptedEndPoint._flushRequiresFillToProgress)
199 _decryptedEndPoint._flushRequiresFillToProgress = false;
200 getExecutor().execute(_runCompletWrite);
205 LOG.debug("onFillable exit {}", _decryptedEndPoint);
209 public void onFillInterestedFailed(Throwable cause)
211 // this means that the fill interest in encrypted bytes has failed.
212 // However we do not handle that here on this callback, but instead wakeup
213 // the decrypted readInterest and/or writeFlusher so that they will attempt
214 // to do the fill and/or flush again and these calls will do the actually
216 _decryptedEndPoint.getFillInterest().onFail(cause);
218 boolean failFlusher = false;
219 synchronized(_decryptedEndPoint)
221 if (_decryptedEndPoint._flushRequiresFillToProgress)
223 _decryptedEndPoint._flushRequiresFillToProgress = false;
228 _decryptedEndPoint.getWriteFlusher().onFail(cause);
232 public String toString()
234 ByteBuffer b = _encryptedInput;
235 int ei=b==null?-1:b.remaining();
236 b = _encryptedOutput;
237 int eo=b==null?-1:b.remaining();
239 int di=b==null?-1:b.remaining();
241 return String.format("SslConnection@%x{%s,eio=%d/%d,di=%d} -> %s",
243 _sslEngine.getHandshakeStatus(),
245 _decryptedEndPoint.getConnection());
248 public class DecryptedEndPoint extends AbstractEndPoint
250 private boolean _fillRequiresFlushToProgress;
251 private boolean _flushRequiresFillToProgress;
252 private boolean _cannotAcceptMoreAppDataToFlush;
253 private boolean _handshaken;
254 private boolean _underFlown;
255 private boolean _peeking = _sslFactory != null;
257 private final Callback _writeCallback = new Callback()
260 public void succeeded()
262 // This means that a write of encrypted data has completed. Writes are done
263 // only if there is a pending writeflusher or a read needed to write
264 // data. In either case the appropriate callback is passed on.
265 boolean fillable = false;
266 synchronized (DecryptedEndPoint.this)
269 LOG.debug("write.complete {}", SslConnection.this.getEndPoint());
271 releaseEncryptedOutputBuffer();
273 _cannotAcceptMoreAppDataToFlush = false;
275 if (_fillRequiresFlushToProgress)
277 _fillRequiresFlushToProgress = false;
282 getFillInterest().fillable();
283 getExecutor().execute(_runCompletWrite);
287 public void failed(final Throwable x)
289 // This means that a write of data has failed. Writes are done
290 // only if there is an active writeflusher or a read needed to write
291 // data. In either case the appropriate callback is passed on.
292 boolean fail_filler = false;
293 synchronized (DecryptedEndPoint.this)
296 LOG.debug("{} write.failed", SslConnection.this, x);
297 BufferUtil.clear(_encryptedOutput);
298 releaseEncryptedOutputBuffer();
300 _cannotAcceptMoreAppDataToFlush = false;
302 if (_fillRequiresFlushToProgress)
304 _fillRequiresFlushToProgress = false;
309 final boolean filler_failed=fail_filler;
311 failedCallback(new Callback()
314 public void succeeded()
319 public void failed(Throwable x)
322 getFillInterest().onFail(x);
323 getWriteFlusher().onFail(x);
330 public DecryptedEndPoint()
332 super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
333 setIdleTimeout(getEndPoint().getIdleTimeout());
337 protected FillInterest getFillInterest()
339 return super.getFillInterest();
343 public void setIdleTimeout(long idleTimeout)
345 super.setIdleTimeout(idleTimeout);
346 getEndPoint().setIdleTimeout(idleTimeout);
350 protected WriteFlusher getWriteFlusher()
352 return super.getWriteFlusher();
356 protected void onIncompleteFlush()
358 // This means that the decrypted endpoint write method was called and not
359 // all data could be wrapped. So either we need to write some encrypted data,
360 // OR if we are handshaking we need to read some encrypted data OR
361 // if neither then we should just try the flush again.
362 boolean try_again = false;
363 synchronized (DecryptedEndPoint.this)
366 LOG.debug("onIncompleteFlush {}", getEndPoint());
367 // If we have pending output data,
368 if (BufferUtil.hasContent(_encryptedOutput))
371 _cannotAcceptMoreAppDataToFlush = true;
372 getEndPoint().write(_writeCallback, _encryptedOutput);
374 // If we are handshaking and need to read,
375 else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
377 // check if we are actually read blocked in order to write
378 _flushRequiresFillToProgress = true;
379 SslConnection.this.fillInterested();
383 // We can get here because the WriteFlusher might not see progress
384 // when it has just flushed the encrypted data, but not consumed anymore
385 // of the application buffers. This is mostly avoided by another iteration
386 // within DecryptedEndPoint flush(), but I cannot convince myself that
387 // this is never ever the case.
395 // If the output is closed,
396 if (isOutputShutdown())
398 // don't bother writing, just notify of close
399 getWriteFlusher().onClose();
404 // try to flush what is pending
405 // because this is a special case (see above) we could probably
406 // avoid the dispatch, but best to be sure
407 getExecutor().execute(_runCompletWrite);
413 protected boolean needsFill() throws IOException
415 // This means that the decrypted data consumer has called the fillInterested
416 // method on the DecryptedEndPoint, so we have to work out if there is
417 // decrypted data to be filled or what callbacks to setup to be told when there
418 // might be more encrypted data available to attempt another call to fill
420 synchronized (DecryptedEndPoint.this)
422 // Do we already have some app data, then app can fill now so return true
423 if (BufferUtil.hasContent(_decryptedInput))
426 // If we have no encrypted data to decrypt OR we have some, but it is not enough
427 if (BufferUtil.isEmpty(_encryptedInput) || _underFlown)
429 // We are not ready to read data
431 // Are we actually write blocked?
432 if (_fillRequiresFlushToProgress)
434 // we must be blocked trying to write before we can read
436 // Do we have data to write
437 if (BufferUtil.hasContent(_encryptedOutput))
440 _cannotAcceptMoreAppDataToFlush = true;
441 getEndPoint().write(_writeCallback, _encryptedOutput);
445 // we have already written the net data
446 // pretend we are readable so the wrap is done by next readable callback
447 _fillRequiresFlushToProgress = false;
453 // Normal readable callback
454 // Get called back on onfillable when then is more data to fill
455 SslConnection.this.fillInterested();
462 // We are ready to read data
469 public void setConnection(Connection connection)
471 if (connection instanceof AbstractConnection)
473 AbstractConnection a = (AbstractConnection)connection;
474 if (a.getInputBufferSize()<_sslEngine.getSession().getApplicationBufferSize())
475 a.setInputBufferSize(_sslEngine.getSession().getApplicationBufferSize());
477 super.setConnection(connection);
480 public SslConnection getSslConnection()
482 return SslConnection.this;
486 public synchronized int fill(ByteBuffer buffer) throws IOException
489 LOG.debug("{} fill enter", SslConnection.this);
492 // Do we already have some decrypted data?
493 if (BufferUtil.hasContent(_decryptedInput))
494 return BufferUtil.append(buffer,_decryptedInput);
496 // We will need a network buffer
497 if (_encryptedInput == null)
498 _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
500 BufferUtil.compact(_encryptedInput);
502 // We also need an app buffer, but can use the passed buffer if it is big enough
504 if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
506 else if (_decryptedInput == null)
507 app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
509 app_in = _decryptedInput;
511 // loop filling and unwrapping until we have something
514 // Let's try reading some encrypted data... even if we have some already.
515 int net_filled = getEndPoint().fill(_encryptedInput);
517 LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled);
519 decryption: while (true)
521 // Let's unwrap even if we have no net data because in that
522 // case we want to fall through to the handshake handling
523 int pos = BufferUtil.flipToFill(app_in);
524 SSLEngineResult unwrapResult;
527 unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
531 BufferUtil.flipToFlush(app_in, pos);
534 LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
536 HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
537 HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
538 Status unwrapResultStatus = unwrapResult.getStatus();
540 // Extra check on unwrapResultStatus == OK with zero length buffer is due
541 // to SSL client on android (see bug #454773)
542 _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0;
552 switch (unwrapResultStatus)
556 switch (handshakeStatus)
558 case NOT_HANDSHAKING:
560 // We were not handshaking, so just tell the app we are closed
565 _sslEngine.getDelegatedTask().run();
570 // We need to send some handshake data (probably the close handshake).
571 // We return -1 so that the application can drive the close by flushing
572 // or shutting down the output.
577 // We expected to read more, but we got closed.
578 // Return -1 to indicate to the application to drive the close.
583 throw new IllegalStateException();
587 case BUFFER_UNDERFLOW:
590 if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
594 LOG.debug("{} {} handshake completed", SslConnection.this,
595 _sslEngine.getUseClientMode() ? "client-side" : "resumed session server-side");
598 // Check whether renegotiation is allowed
599 if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
602 LOG.debug("{} renegotiation denied", SslConnection.this);
607 // If bytes were produced, don't bother with the handshake status;
608 // pass the decrypted data to the application, which will perform
609 // another call to fill() or flush().
610 if (unwrapResult.bytesProduced() > 0)
612 if (app_in == buffer)
613 return unwrapResult.bytesProduced();
614 return BufferUtil.append(buffer,_decryptedInput);
617 switch (handshakeStatus)
619 case NOT_HANDSHAKING:
627 _sslEngine.getDelegatedTask().run();
630 _sslEngine = _sslFactory.restartSSL(_sslEngine.getHandshakeSession());
631 _encryptedInput.position(0);
639 // If we are called from flush()
640 // return to let it do the wrapping.
641 if (buffer == __FLUSH_CALLED_FILL)
644 _fillRequiresFlushToProgress = true;
645 flush(__FILL_CALLED_FLUSH);
646 if (BufferUtil.isEmpty(_encryptedOutput))
648 // The flush wrote all the encrypted bytes so continue to fill
649 _fillRequiresFlushToProgress = false;
654 // The flush did not complete, return from fill()
655 // and let the write completion mechanism to kick in.
667 throw new IllegalStateException();
673 throw new IllegalStateException();
686 // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
687 if (_flushRequiresFillToProgress)
689 _flushRequiresFillToProgress = false;
690 getExecutor().execute(_runCompletWrite);
693 if (_encryptedInput != null && !_encryptedInput.hasRemaining())
695 _bufferPool.release(_encryptedInput);
696 _encryptedInput = null;
698 if (_decryptedInput != null && !_decryptedInput.hasRemaining())
700 _bufferPool.release(_decryptedInput);
701 _decryptedInput = null;
704 LOG.debug("{} fill exit", SslConnection.this);
708 private void closeInbound()
712 _sslEngine.closeInbound();
714 catch (SSLException x)
721 public synchronized boolean flush(ByteBuffer... appOuts) throws IOException
723 // The contract for flush does not require that all appOuts bytes are written
724 // or even that any appOut bytes are written! If the connection is write block
725 // or busy handshaking, then zero bytes may be taken from appOuts and this method
726 // will return 0 (even if some handshake bytes were flushed and filled).
727 // it is the applications responsibility to call flush again - either in a busy loop
728 // or better yet by using EndPoint#write to do the flushing.
731 LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts));
735 if (_cannotAcceptMoreAppDataToFlush)
737 if (_sslEngine.isOutboundDone())
738 throw new EofException(new ClosedChannelException());
742 // We will need a network buffer
743 if (_encryptedOutput == null)
744 _encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
748 // We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
749 BufferUtil.compact(_encryptedOutput);
750 int pos = BufferUtil.flipToFill(_encryptedOutput);
751 SSLEngineResult wrapResult;
754 wrapResult=_sslEngine.wrap(appOuts, _encryptedOutput);
758 BufferUtil.flipToFlush(_encryptedOutput, pos);
762 LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
763 if (wrapResult.bytesConsumed()>0)
764 consumed+=wrapResult.bytesConsumed();
765 Status wrapResultStatus = wrapResult.getStatus();
767 boolean allConsumed=true;
768 for (ByteBuffer b : appOuts)
769 if (BufferUtil.hasContent(b))
772 // and deal with the results returned from the sslEngineWrap
773 switch (wrapResultStatus)
776 // The SSL engine has close, but there may be close handshake that needs to be written
777 if (BufferUtil.hasContent(_encryptedOutput))
779 _cannotAcceptMoreAppDataToFlush = true;
780 getEndPoint().flush(_encryptedOutput);
781 getEndPoint().shutdownOutput();
782 // If we failed to flush the close handshake then we will just pretend that
783 // the write has progressed normally and let a subsequent call to flush
784 // (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
785 // The caller will find out about the close on a subsequent flush or fill.
786 if (BufferUtil.hasContent(_encryptedOutput))
789 // otherwise we have written, and the caller will close the underlying connection
792 getEndPoint().shutdownOutput();
796 case BUFFER_UNDERFLOW:
797 throw new IllegalStateException();
801 LOG.debug("{} {} {}", this, wrapResultStatus, BufferUtil.toDetailString(_encryptedOutput));
803 if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
807 LOG.debug("{} {} handshake completed", SslConnection.this, "server-side");
810 HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
812 // Check whether renegotiation is allowed
813 if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
816 LOG.debug("{} renegotiation denied", SslConnection.this);
817 getEndPoint().shutdownOutput();
821 // if we have net bytes, let's try to flush them
822 if (BufferUtil.hasContent(_encryptedOutput))
823 if (!getEndPoint().flush(_encryptedOutput))
824 getEndPoint().flush(_encryptedOutput); // one retry
826 // But we also might have more to do for the handshaking state.
827 switch (handshakeStatus)
829 case NOT_HANDSHAKING:
830 // If we have not consumed all and had just finished handshaking, then we may
831 // have just flushed the last handshake in the encrypted buffers, so we should
833 if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
836 // Return true if we consumed all the bytes and encrypted are all flushed
837 return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
840 // run the task and continue
841 _sslEngine.getDelegatedTask().run();
845 // Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
849 // Ah we need to fill some data so we can write.
850 // So if we were not called from fill and the app is not reading anyway
851 if (appOuts[0]!=__FILL_CALLED_FLUSH && !getFillInterest().isInterested())
853 // Tell the onFillable method that there might be a write to complete
854 _flushRequiresFillToProgress = true;
855 fill(__FLUSH_CALLED_FILL);
856 // Check if after the fill() we need to wrap again
857 if (handshakeStatus == HandshakeStatus.NEED_WRAP)
860 return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
863 throw new IllegalStateException();
871 LOG.debug("{} flush exit, consumed {}", SslConnection.this, consumed);
872 releaseEncryptedOutputBuffer();
876 private void releaseEncryptedOutputBuffer()
878 if (!Thread.holdsLock(DecryptedEndPoint.this))
879 throw new IllegalStateException();
880 if (_encryptedOutput != null && !_encryptedOutput.hasRemaining())
882 _bufferPool.release(_encryptedOutput);
883 _encryptedOutput = null;
888 public void shutdownOutput()
890 boolean ishut = isInputShutdown();
891 boolean oshut = isOutputShutdown();
893 LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, oshut, ishut);
896 // Aggressively close, since inbound close alert has already been processed
897 // and the TLS specification allows to close the connection directly, which
898 // is what most other implementations expect: a FIN rather than a TLS close
899 // reply. If a TLS close reply is sent, most implementations send a RST.
900 getEndPoint().close();
906 _sslEngine.closeOutbound();
907 flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
908 SslConnection.this.fillInterested(); // seek reply FIN or RST or close handshake
913 getEndPoint().close();
919 public boolean isOutputShutdown()
921 return _sslEngine.isOutboundDone() || getEndPoint().isOutputShutdown();
928 // First send the TLS Close Alert, then the FIN
930 getEndPoint().close();
934 public boolean isOpen()
936 return getEndPoint().isOpen();
940 public Object getTransport()
942 return getEndPoint();
946 public boolean isInputShutdown()
948 return _sslEngine.isInboundDone();
952 public String toString()
954 return super.toString()+"->"+getEndPoint().toString();