View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.io.ssl;
20  
21  import java.io.IOException;
22  import java.net.SocketException;
23  import java.nio.ByteBuffer;
24  import java.nio.channels.ClosedChannelException;
25  import java.util.Arrays;
26  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;
32  
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.SocketBased;
43  import org.eclipse.jetty.io.WriteFlusher;
44  import org.eclipse.jetty.util.BufferUtil;
45  import org.eclipse.jetty.util.Callback;
46  import org.eclipse.jetty.util.log.Log;
47  import org.eclipse.jetty.util.log.Logger;
48  
49  /**
50   * A Connection that acts as an interceptor between an EndPoint providing SSL encrypted data
51   * and another consumer of an EndPoint (typically an {@link Connection} like HttpConnection) that
52   * wants unencrypted data.
53   * <p>
54   * The connector uses an {@link EndPoint} (typically {@link SelectChannelEndPoint}) as
55   * it's source/sink of encrypted data.   It then provides an endpoint via {@link #getDecryptedEndPoint()} to
56   * expose a source/sink of unencrypted data to another connection (eg HttpConnection).
57   * <p>
58   * The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any
59   * asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
60   * <p>
61   * The passive methods are {@link DecryptedEndPoint#fill(ByteBuffer)} and {@link DecryptedEndPoint#flush(ByteBuffer...)}. They make best
62   * effort attempts to progress the connection using only calls to the encrypted {@link EndPoint#fill(ByteBuffer)} and {@link EndPoint#flush(ByteBuffer...)}
63   * methods.  They will never block nor schedule any readInterest or write callbacks.   If a fill/flush cannot progress either because
64   * of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
65   * Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
66   * encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Callback)}.
67   * <p>
68   * It is only the active methods : {@link DecryptedEndPoint#fillInterested(Callback)} and
69   * {@link DecryptedEndPoint#write(Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
70   * {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Callback, ByteBuffer...)}
71   * methods.  For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
72   * write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
73   * to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
74   * <p>
75   * MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing
76   * themselves.  Instead they simple make the callbacks to the decrypted callbacks, so that the passive encrypted fill/flush will
77   * be called again and make another best effort attempt to progress the connection.
78   *
79   */
80  public class SslConnection extends AbstractConnection
81  {
82      private static final Logger LOG = Log.getLogger(SslConnection.class);
83      private static final boolean DEBUG = LOG.isDebugEnabled(); // Easy for the compiler to remove the code if DEBUG==false
84      private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0);
85      private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0);
86      private final ByteBufferPool _bufferPool;
87      private final SSLEngine _sslEngine;
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()
95      {
96          @Override
97          public void run()
98          {
99              _decryptedEndPoint.getWriteFlusher().completeWrite();
100         }
101     };
102     private boolean _renegotiationAllowed;
103 
104     public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine)
105     {
106         // This connection does not execute calls to onfillable, so they will be called by the selector thread.
107         // onfillable does not block and will only wakeup another thread to do the actual reading and handling.
108         super(endPoint, executor, !EXECUTE_ONFILLABLE);
109         this._bufferPool = byteBufferPool;
110         this._sslEngine = sslEngine;
111         this._decryptedEndPoint = newDecryptedEndPoint();
112 
113         if (endPoint instanceof SocketBased)
114         {
115             try
116             {
117                 ((SocketBased)endPoint).getSocket().setSoLinger(true, 30000);
118             }
119             catch (SocketException e)
120             {
121                 throw new RuntimeIOException(e);
122             }
123         }
124     }
125 
126     protected DecryptedEndPoint newDecryptedEndPoint()
127     {
128         return new DecryptedEndPoint();
129     }
130 
131     public SSLEngine getSSLEngine()
132     {
133         return _sslEngine;
134     }
135 
136     public DecryptedEndPoint getDecryptedEndPoint()
137     {
138         return _decryptedEndPoint;
139     }
140 
141     public boolean isRenegotiationAllowed()
142     {
143         return _renegotiationAllowed;
144     }
145 
146     public void setRenegotiationAllowed(boolean renegotiationAllowed)
147     {
148         this._renegotiationAllowed = renegotiationAllowed;
149     }
150 
151     @Override
152     public void onOpen()
153     {
154         try
155         {
156             // Begin the handshake
157             _sslEngine.beginHandshake();
158             super.onOpen();
159             getDecryptedEndPoint().getConnection().onOpen();
160         }
161         catch (SSLException x)
162         {
163             getEndPoint().close();
164             throw new RuntimeIOException(x);
165         }
166     }
167 
168     @Override
169     public void onClose()
170     {
171         _decryptedEndPoint.getConnection().onClose();
172         super.onClose();
173     }
174 
175     @Override
176     public void close()
177     {
178         getDecryptedEndPoint().getConnection().close();
179     }
180 
181     @Override
182     public void onFillable()
183     {
184         // onFillable means that there are encrypted bytes ready to be filled.
185         // however we do not fill them here on this callback, but instead wakeup
186         // the decrypted readInterest and/or writeFlusher so that they will attempt
187         // to do the fill and/or flush again and these calls will do the actually
188         // filling.
189 
190         if (DEBUG)
191             LOG.debug("onFillable enter {}", getEndPoint());
192 
193         // We have received a close handshake, close the end point to send FIN.
194         if (_decryptedEndPoint.isInputShutdown())
195             getEndPoint().close();
196             
197         // wake up whoever is doing the fill or the flush so they can
198         // do all the filling, unwrapping, wrapping and flushing
199         _decryptedEndPoint.getFillInterest().fillable();
200 
201         // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
202         synchronized(_decryptedEndPoint)
203         {
204             if (_decryptedEndPoint._flushRequiresFillToProgress)
205             {
206                 _decryptedEndPoint._flushRequiresFillToProgress = false;
207                 getExecutor().execute(_runCompletWrite);
208             }
209         }
210 
211         if (DEBUG)
212             LOG.debug("onFillable exit {}", getEndPoint());
213     }
214 
215     @Override
216     public void onFillInterestedFailed(Throwable cause)
217     {
218         // this means that the fill interest in encrypted bytes has failed.
219         // However we do not handle that here on this callback, but instead wakeup
220         // the decrypted readInterest and/or writeFlusher so that they will attempt
221         // to do the fill and/or flush again and these calls will do the actually
222         // handle the cause.
223         _decryptedEndPoint.getFillInterest().onFail(cause);
224 
225         boolean failFlusher = false;
226         synchronized(_decryptedEndPoint)
227         {
228             if (_decryptedEndPoint._flushRequiresFillToProgress)
229             {
230                 _decryptedEndPoint._flushRequiresFillToProgress = false;
231                 failFlusher = true;
232             }
233         }
234         if (failFlusher)
235             _decryptedEndPoint.getWriteFlusher().onFail(cause);
236     }
237 
238     @Override
239     public String toString()
240     {
241         ByteBuffer b = _encryptedInput;
242         int ei=b==null?-1:b.remaining();
243         b = _encryptedOutput;
244         int eo=b==null?-1:b.remaining();
245         b = _decryptedInput;
246         int di=b==null?-1:b.remaining();
247 
248         return String.format("SslConnection@%x{%s,eio=%d/%d,di=%d} -> %s",
249                 hashCode(),
250                 _sslEngine.getHandshakeStatus(),
251                 ei,eo,di,
252                 _decryptedEndPoint.getConnection());
253     }
254 
255     public class DecryptedEndPoint extends AbstractEndPoint
256     {
257         private boolean _fillRequiresFlushToProgress;
258         private boolean _flushRequiresFillToProgress;
259         private boolean _cannotAcceptMoreAppDataToFlush;
260         private boolean _handshaken;
261         private boolean _underFlown;
262 
263         private final Callback _writeCallback = new Callback()
264         {
265             @Override
266             public void succeeded()
267             {
268                 // This means that a write of encrypted data has completed.  Writes are done
269                 // only if there is a pending writeflusher or a read needed to write
270                 // data.  In either case the appropriate callback is passed on.
271                 boolean fillable = false;
272                 synchronized (DecryptedEndPoint.this)
273                 {
274                     if (DEBUG)
275                         LOG.debug("write.complete {}", SslConnection.this.getEndPoint());
276 
277                     releaseEncryptedOutputBuffer();
278 
279                     _cannotAcceptMoreAppDataToFlush = false;
280 
281                     if (_fillRequiresFlushToProgress)
282                     {
283                         _fillRequiresFlushToProgress = false;
284                         fillable = true;
285                     }
286                 }
287                 if (fillable)
288                     getFillInterest().fillable();
289                 getExecutor().execute(_runCompletWrite);
290             }
291 
292             @Override
293             public void failed(Throwable x)
294             {
295                 // This means that a write of data has failed.  Writes are done
296                 // only if there is an active writeflusher or a read needed to write
297                 // data.  In either case the appropriate callback is passed on.
298                 boolean failFiller = false;
299                 synchronized (DecryptedEndPoint.this)
300                 {
301                     if (DEBUG)
302                         LOG.debug("{} write.failed", SslConnection.this, x);
303                     BufferUtil.clear(_encryptedOutput);
304                     releaseEncryptedOutputBuffer();
305 
306                     _cannotAcceptMoreAppDataToFlush = false;
307 
308                     if (_fillRequiresFlushToProgress)
309                     {
310                         _fillRequiresFlushToProgress = false;
311                         failFiller = true;
312                     }
313                 }
314                 if (failFiller)
315                     getFillInterest().onFail(x);
316                 getWriteFlusher().onFail(x);
317             }
318         };
319 
320         public DecryptedEndPoint()
321         {
322             super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
323             setIdleTimeout(getEndPoint().getIdleTimeout());
324         }
325 
326         @Override
327         protected FillInterest getFillInterest()
328         {
329             return super.getFillInterest();
330         }
331 
332         @Override
333         public void setIdleTimeout(long idleTimeout)
334         {
335             super.setIdleTimeout(idleTimeout);
336             getEndPoint().setIdleTimeout(idleTimeout);
337         }
338 
339         @Override
340         protected WriteFlusher getWriteFlusher()
341         {
342             return super.getWriteFlusher();
343         }
344 
345         @Override
346         protected void onIncompleteFlush()
347         {
348             // This means that the decrypted endpoint write method was called and not
349             // all data could be wrapped. So either we need to write some encrypted data,
350             // OR if we are handshaking we need to read some encrypted data OR
351             // if neither then we should just try the flush again.
352             boolean flush = false;
353             synchronized (DecryptedEndPoint.this)
354             {
355                 if (DEBUG)
356                     LOG.debug("onIncompleteFlush {}", getEndPoint());
357                 // If we have pending output data,
358                 if (BufferUtil.hasContent(_encryptedOutput))
359                 {
360                     // write it
361                     _cannotAcceptMoreAppDataToFlush = true;
362                     getEndPoint().write(_writeCallback, _encryptedOutput);
363                 }
364                 // If we are handshaking and need to read,
365                 else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
366                 {
367                     // check if we are actually read blocked in order to write
368                     _flushRequiresFillToProgress = true;
369                     SslConnection.this.fillInterested();
370                 }
371                 else
372                 {
373                     flush = true;
374                 }
375             }
376             if (flush)
377             {
378                 // If the output is closed,
379                 if (isOutputShutdown())
380                 {
381                     // don't bother writing, just notify of close
382                     getWriteFlusher().onClose();
383                 }
384                 // Else,
385                 else
386                 {
387                     // try to flush what is pending
388                     getWriteFlusher().completeWrite();
389                 }
390             }
391         }
392 
393         @Override
394         protected boolean needsFill() throws IOException
395         {
396             // This means that the decrypted data consumer has called the fillInterested
397             // method on the DecryptedEndPoint, so we have to work out if there is
398             // decrypted data to be filled or what callbacks to setup to be told when there
399             // might be more encrypted data available to attempt another call to fill
400 
401             synchronized (DecryptedEndPoint.this)
402             {
403                 // Do we already have some app data, then app can fill now so return true
404                 if (BufferUtil.hasContent(_decryptedInput))
405                     return true;
406 
407                 // If we have no encrypted data to decrypt OR we have some, but it is not enough
408                 if (BufferUtil.isEmpty(_encryptedInput) || _underFlown)
409                 {
410                     // We are not ready to read data
411 
412                     // Are we actually write blocked?
413                     if (_fillRequiresFlushToProgress)
414                     {
415                         // we must be blocked trying to write before we can read
416 
417                         // Do we have data to write
418                         if (BufferUtil.hasContent(_encryptedOutput))
419                         {
420                             // write it
421                             _cannotAcceptMoreAppDataToFlush = true;
422                             getEndPoint().write(_writeCallback, _encryptedOutput);
423                         }
424                         else
425                         {
426                             // we have already written the net data
427                             // pretend we are readable so the wrap is done by next readable callback
428                             _fillRequiresFlushToProgress = false;
429                             return true;
430                         }
431                     }
432                     else
433                     {
434                         // Normal readable callback
435                         // Get called back on onfillable when then is more data to fill
436                         SslConnection.this.fillInterested();
437                     }
438 
439                     return false;
440                 }
441                 else
442                 {
443                     // We are ready to read data
444                     return true;
445                 }
446             }
447         }
448 
449         @Override
450         public void setConnection(Connection connection)
451         {
452             if (connection instanceof AbstractConnection)
453             {
454                 AbstractConnection a = (AbstractConnection)connection;
455                 if (a.getInputBufferSize()<_sslEngine.getSession().getApplicationBufferSize())
456                     a.setInputBufferSize(_sslEngine.getSession().getApplicationBufferSize());
457             }
458             super.setConnection(connection);
459         }
460 
461         public SslConnection getSslConnection()
462         {
463             return SslConnection.this;
464         }
465 
466         @Override
467         public synchronized int fill(ByteBuffer buffer) throws IOException
468         {
469             if (DEBUG)
470                 LOG.debug("{} fill enter", SslConnection.this);
471             try
472             {
473                 // Do we already have some decrypted data?
474                 if (BufferUtil.hasContent(_decryptedInput))
475                     return BufferUtil.flipPutFlip(_decryptedInput, buffer);
476 
477                 // We will need a network buffer
478                 if (_encryptedInput == null)
479                     _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
480                 else
481                     BufferUtil.compact(_encryptedInput);
482 
483                 // We also need an app buffer, but can use the passed buffer if it is big enough
484                 ByteBuffer app_in;
485                 if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
486                     app_in = buffer;
487                 else if (_decryptedInput == null)
488                     app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
489                 else
490                     app_in = _decryptedInput;
491 
492                 // loop filling and unwrapping until we have something
493                 while (true)
494                 {
495                     // Let's try reading some encrypted data... even if we have some already.
496                     int net_filled = getEndPoint().fill(_encryptedInput);
497                     if (DEBUG)
498                         LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled);
499                     if (net_filled > 0)
500                         _underFlown = false;
501 
502                     // Let's try the SSL thang even if we have no net data because in that
503                     // case we want to fall through to the handshake handling
504                     int pos = BufferUtil.flipToFill(app_in);
505 
506                     SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
507 
508                     BufferUtil.flipToFlush(app_in, pos);
509                     if (DEBUG)
510                         LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
511 
512                     Status unwrapResultStatus = unwrapResult.getStatus();
513                     HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
514                     HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
515 
516                     // and deal with the results
517                     switch (unwrapResultStatus)
518                     {
519                         case BUFFER_OVERFLOW:
520                             throw new IllegalStateException();
521 
522                         case CLOSED:
523                             // Dang! we have to care about the handshake state specially for close
524                             switch (handshakeStatus)
525                             {
526                                 case NOT_HANDSHAKING:
527                                     // We were not handshaking, so just tell the app we are closed
528                                     return -1;
529 
530                                 case NEED_TASK:
531                                     // run the task
532                                     _sslEngine.getDelegatedTask().run();
533                                     continue;
534 
535                                 case NEED_WRAP:
536                                     // we need to send some handshake data (probably to send a close handshake).
537                                     // but that will not enable any extra data to fill, so we just return -1
538                                     // The wrapping can be done by any output drivers doing flushing or shutdown output.
539                                     return -1;
540                             }
541                             throw new IllegalStateException();
542 
543                         default:
544                             if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
545                             {
546                                 _handshaken = true;
547                                 if (DEBUG)
548                                     LOG.debug("{} handshake completed client-side", SslConnection.this);
549                             }
550 
551                             // Check whether renegotiation is allowed
552                             if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
553                             {
554                                 if (DEBUG)
555                                     LOG.debug("{} renegotiation denied", SslConnection.this);
556                                 closeInbound();
557                                 return -1;
558                             }
559 
560                             if (unwrapResultStatus == Status.BUFFER_UNDERFLOW)
561                                 _underFlown = true;
562 
563                             // If bytes were produced, don't bother with the handshake status;
564                             // pass the decrypted data to the application, which will perform
565                             // another call to fill() or flush().
566                             if (unwrapResult.bytesProduced() > 0)
567                             {
568                                 if (app_in == buffer)
569                                     return unwrapResult.bytesProduced();
570                                 return BufferUtil.flipPutFlip(_decryptedInput, buffer);
571                             }
572 
573                             // Dang! we have to care about the handshake state
574                             switch (handshakeStatus)
575                             {
576                                 case NOT_HANDSHAKING:
577                                     // we just didn't read anything.
578                                     if (net_filled < 0)
579                                     {
580                                         closeInbound();
581                                         return -1;
582                                     }
583                                     return 0;
584 
585                                 case NEED_TASK:
586                                     // run the task
587                                     _sslEngine.getDelegatedTask().run();
588                                     continue;
589 
590                                 case NEED_WRAP:
591                                     // we need to send some handshake data
592 
593                                     // if we are called from flush
594                                     if (buffer == __FLUSH_CALLED_FILL)
595                                         return 0; // let it do the wrapping
596 
597                                     _fillRequiresFlushToProgress = true;
598                                     flush(__FILL_CALLED_FLUSH);
599                                     if (BufferUtil.isEmpty(_encryptedOutput))
600                                     {
601                                         // the flush completed so continue
602                                         _fillRequiresFlushToProgress = false;
603                                         continue;
604                                     }
605                                     return 0;
606 
607                                 case NEED_UNWRAP:
608                                     // if we just filled some net data
609                                     if (net_filled < 0)
610                                     {
611                                         closeInbound();
612                                         return -1;
613                                     }
614                                     else if (net_filled > 0)
615                                     {
616                                         // maybe we will fill some more on a retry
617                                         continue;
618                                     }
619                                     else
620                                     {
621                                         if (_encryptedInput.hasRemaining())
622                                         {
623                                             // if there are more encrypted bytes,
624                                             // then we need to unwrap more, we don't
625                                             // care if net_filled is zero
626                                             continue;
627                                         }
628                                         // we need to wait for more net data
629                                         return 0;
630                                     }
631 
632                                 case FINISHED:
633                                     throw new IllegalStateException();
634                             }
635                     }
636                 }
637             }
638             catch (SSLException e)
639             {
640                 getEndPoint().close();
641                 throw new EofException(e);
642             }
643             catch (Exception e)
644             {
645                 getEndPoint().close();
646                 throw e;
647             }
648             finally
649             {
650                 // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
651                 if (_flushRequiresFillToProgress)
652                 {
653                     _flushRequiresFillToProgress = false;
654                     getExecutor().execute(_runCompletWrite);
655                 }
656 
657                 if (_encryptedInput != null && !_encryptedInput.hasRemaining())
658                 {
659                     _bufferPool.release(_encryptedInput);
660                     _encryptedInput = null;
661                 }
662                 if (_decryptedInput != null && !_decryptedInput.hasRemaining())
663                 {
664                     _bufferPool.release(_decryptedInput);
665                     _decryptedInput = null;
666                 }
667                 if (DEBUG)
668                     LOG.debug("{} fill exit", SslConnection.this);
669             }
670         }
671 
672         private void closeInbound()
673         {
674             try
675             {
676                 _sslEngine.closeInbound();
677             }
678             catch (SSLException x)
679             {
680                 LOG.ignore(x);
681             }
682         }
683 
684         @Override
685         public synchronized boolean flush(ByteBuffer... appOuts) throws IOException
686         {
687             // The contract for flush does not require that all appOuts bytes are written
688             // or even that any appOut bytes are written!  If the connection is write block
689             // or busy handshaking, then zero bytes may be taken from appOuts and this method
690             // will return 0 (even if some handshake bytes were flushed and filled).
691             // it is the applications responsibility to call flush again - either in a busy loop
692             // or better yet by using EndPoint#write to do the flushing.
693 
694             if (DEBUG)
695                 LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts));
696             int consumed=0;
697             try
698             {
699                 if (_cannotAcceptMoreAppDataToFlush)
700                 {
701                     if (_sslEngine.isOutboundDone())
702                         throw new EofException(new ClosedChannelException());
703                     return false;
704                 }
705 
706                 // We will need a network buffer
707                 if (_encryptedOutput == null)
708                     _encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
709 
710                 while (true)
711                 {
712                     // We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
713                     BufferUtil.compact(_encryptedOutput);
714                     int pos = BufferUtil.flipToFill(_encryptedOutput);
715                     SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
716                     if (DEBUG)
717                         LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
718                     BufferUtil.flipToFlush(_encryptedOutput, pos);
719                     if (wrapResult.bytesConsumed()>0)
720                         consumed+=wrapResult.bytesConsumed();
721 
722                     boolean allConsumed=true;
723                     // clear empty buffers to prevent position creeping up the buffer
724                     for (ByteBuffer b : appOuts)
725                     {
726                         if (BufferUtil.isEmpty(b))
727                             BufferUtil.clear(b);
728                         else
729                             allConsumed=false;
730                     }
731 
732                     Status wrapResultStatus = wrapResult.getStatus();
733 
734                     // and deal with the results returned from the sslEngineWrap
735                     switch (wrapResultStatus)
736                     {
737                         case CLOSED:
738                             // The SSL engine has close, but there may be close handshake that needs to be written
739                             if (BufferUtil.hasContent(_encryptedOutput))
740                             {
741                                 _cannotAcceptMoreAppDataToFlush = true;
742                                 getEndPoint().flush(_encryptedOutput);
743                                 getEndPoint().shutdownOutput();
744                                 // If we failed to flush the close handshake then we will just pretend that
745                                 // the write has progressed normally and let a subsequent call to flush
746                                 // (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
747                                 // The caller will find out about the close on a subsequent flush or fill.
748                                 if (BufferUtil.hasContent(_encryptedOutput))
749                                     return false;
750                             }
751                             // otherwise we have written, and the caller will close the underlying connection
752                             else
753                             {
754                                 getEndPoint().shutdownOutput();
755                             }
756                             return allConsumed;
757 
758                         case BUFFER_UNDERFLOW:
759                             throw new IllegalStateException();
760 
761                         default:
762                             if (DEBUG)
763                                 LOG.debug("{} {} {}", this, wrapResultStatus, BufferUtil.toDetailString(_encryptedOutput));
764 
765                             if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
766                             {
767                                 _handshaken = true;
768                                 if (DEBUG)
769                                     LOG.debug("{} handshake completed server-side", SslConnection.this);
770                             }
771 
772                             HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
773 
774                             // Check whether renegotiation is allowed
775                             if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
776                             {
777                                 if (DEBUG)
778                                     LOG.debug("{} renegotiation denied", SslConnection.this);
779                                 shutdownOutput();
780                                 return allConsumed;
781                             }
782 
783                             // if we have net bytes, let's try to flush them
784                             if (BufferUtil.hasContent(_encryptedOutput))
785                                 getEndPoint().flush(_encryptedOutput);
786 
787                             // But we also might have more to do for the handshaking state.
788                             switch (handshakeStatus)
789                             {
790                                 case NOT_HANDSHAKING:
791                                     // Return with the number of bytes consumed (which may be 0)
792                                     return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
793 
794                                 case NEED_TASK:
795                                     // run the task and continue
796                                     _sslEngine.getDelegatedTask().run();
797                                     continue;
798 
799                                 case NEED_WRAP:
800                                     // Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
801                                     continue;
802 
803                                 case NEED_UNWRAP:
804                                     // Ah we need to fill some data so we can write.
805                                     // So if we were not called from fill and the app is not reading anyway
806                                     if (appOuts[0]!=__FILL_CALLED_FLUSH && !getFillInterest().isInterested())
807                                     {
808                                         // Tell the onFillable method that there might be a write to complete
809                                         _flushRequiresFillToProgress = true;
810                                         fill(__FLUSH_CALLED_FILL);
811                                         // Check if after the fill() we need to wrap again
812                                         if (handshakeStatus == HandshakeStatus.NEED_WRAP)
813                                             continue;
814                                     }
815                                     return allConsumed&&BufferUtil.isEmpty(_encryptedOutput);
816 
817                                 case FINISHED:
818                                     throw new IllegalStateException();
819                             }
820                     }
821                 }
822             }
823             catch (Exception e)
824             {
825                 getEndPoint().close();
826                 throw e;
827             }
828             finally
829             {
830                 if (DEBUG)
831                     LOG.debug("{} flush exit, consumed {}", SslConnection.this, consumed);
832                 releaseEncryptedOutputBuffer();
833             }
834         }
835 
836         private void releaseEncryptedOutputBuffer()
837         {
838             if (!Thread.holdsLock(DecryptedEndPoint.this))
839                 throw new IllegalStateException();
840             if (_encryptedOutput != null && !_encryptedOutput.hasRemaining())
841             {
842                 _bufferPool.release(_encryptedOutput);
843                 _encryptedOutput = null;
844             }
845         }
846 
847         @Override
848         public void shutdownOutput()
849         {
850             boolean ishut = isInputShutdown();
851             if (DEBUG)
852                 LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, isOutputShutdown(), ishut);
853             if (ishut)
854             {
855                 // Aggressively close, since inbound close alert has already been processed
856                 // and the TLS specification allows to close the connection directly, which
857                 // is what most other implementations expect: a FIN rather than a TLS close
858                 // reply. If a TLS close reply is sent, most implementation send a RST.
859                 getEndPoint().close();
860             }
861             else
862             {
863                 try
864                 {
865                     _sslEngine.closeOutbound();
866                     flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
867                     SslConnection.this.fillInterested(); // seek reply FIN or RST or close handshake
868                 }
869                 catch (Exception e)
870                 {
871                     LOG.ignore(e);
872                     getEndPoint().close();
873                 }
874             }
875         }
876 
877         @Override
878         public boolean isOutputShutdown()
879         {
880             return _sslEngine.isOutboundDone() || getEndPoint().isOutputShutdown();
881         }
882 
883         @Override
884         public void close()
885         {
886             getEndPoint().close();
887         }
888 
889         @Override
890         public boolean isOpen()
891         {
892             return getEndPoint().isOpen();
893         }
894 
895         @Override
896         public Object getTransport()
897         {
898             return getEndPoint();
899         }
900 
901         @Override
902         public boolean isInputShutdown()
903         {
904             return _sslEngine.isInboundDone();
905         }
906 
907         @Override
908         public String toString()
909         {
910             return super.toString()+"->"+getEndPoint().toString();
911         }
912     }
913 }