View Javadoc

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