View Javadoc

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