X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=lib%2Fjetty%2Forg%2Feclipse%2Fjetty%2Fio%2Fssl%2FSslConnection.java;h=21c8bf3834aefd1de94e887b8d7f7a1b47acd42f;hp=ee9e449b15110bd5e613ca531cda3e2d2600bc8e;hb=065ca60170f2471227dc25784e1a4c3b7912d367;hpb=73ef54a38e3930a1a789cdc6b5fa23cdd4c9d086 diff --git a/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java b/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java index ee9e449b..21c8bf38 100644 --- a/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -83,7 +83,8 @@ public class SslConnection extends AbstractConnection private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0); private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0); private final ByteBufferPool _bufferPool; - private final SSLEngine _sslEngine; + private SSLEngine _sslEngine; + private final SslReconfigurator _sslFactory; private final DecryptedEndPoint _decryptedEndPoint; private ByteBuffer _decryptedInput; private ByteBuffer _encryptedInput; @@ -101,12 +102,17 @@ public class SslConnection extends AbstractConnection private boolean _renegotiationAllowed; public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine) + { + this(byteBufferPool, executor, endPoint, sslEngine, null); + } + public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine, SslReconfigurator fact) { // This connection does not execute calls to onfillable, so they will be called by the selector thread. // onfillable does not block and will only wakeup another thread to do the actual reading and handling. super(endPoint, executor, !EXECUTE_ONFILLABLE); this._bufferPool = byteBufferPool; this._sslEngine = sslEngine; + this._sslFactory = fact; this._decryptedEndPoint = newDecryptedEndPoint(); } @@ -246,6 +252,7 @@ public class SslConnection extends AbstractConnection private boolean _cannotAcceptMoreAppDataToFlush; private boolean _handshaken; private boolean _underFlown; + private boolean _peeking = _sslFactory != null; private final Callback _writeCallback = new Callback() { @@ -305,7 +312,7 @@ public class SslConnection extends AbstractConnection { @Override public void succeeded() - { + { } @Override @@ -315,7 +322,7 @@ public class SslConnection extends AbstractConnection getFillInterest().onFail(x); getWriteFlusher().onFail(x); } - + },x); } }; @@ -352,7 +359,7 @@ public class SslConnection extends AbstractConnection // all data could be wrapped. So either we need to write some encrypted data, // OR if we are handshaking we need to read some encrypted data OR // if neither then we should just try the flush again. - boolean flush = false; + boolean try_again = false; synchronized (DecryptedEndPoint.this) { if (DEBUG) @@ -373,10 +380,17 @@ public class SslConnection extends AbstractConnection } else { - flush = true; + // We can get here because the WriteFlusher might not see progress + // when it has just flushed the encrypted data, but not consumed anymore + // of the application buffers. This is mostly avoided by another iteration + // within DecryptedEndPoint flush(), but I cannot convince myself that + // this is never ever the case. + try_again = true; } } - if (flush) + + + if (try_again) { // If the output is closed, if (isOutputShutdown()) @@ -388,7 +402,9 @@ public class SslConnection extends AbstractConnection else { // try to flush what is pending - getWriteFlusher().completeWrite(); + // because this is a special case (see above) we could probably + // avoid the dispatch, but best to be sure + getExecutor().execute(_runCompletWrite); } } } @@ -480,7 +496,7 @@ public class SslConnection extends AbstractConnection // We will need a network buffer if (_encryptedInput == null) _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); - else + else if(!_peeking) BufferUtil.compact(_encryptedInput); // We also need an app buffer, but can use the passed buffer if it is big enough @@ -505,8 +521,15 @@ public class SslConnection extends AbstractConnection // Let's unwrap even if we have no net data because in that // case we want to fall through to the handshake handling int pos = BufferUtil.flipToFill(app_in); - SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in); - BufferUtil.flipToFlush(app_in, pos); + SSLEngineResult unwrapResult; + try + { + unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in); + } + finally + { + BufferUtil.flipToFlush(app_in, pos); + } if (DEBUG) LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult); @@ -514,7 +537,9 @@ public class SslConnection extends AbstractConnection HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus(); Status unwrapResultStatus = unwrapResult.getStatus(); - _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW; + // Extra check on unwrapResultStatus == OK with zero length buffer is due + // to SSL client on android (see bug #454773) + _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0; if (_underFlown) { @@ -547,6 +572,12 @@ public class SslConnection extends AbstractConnection // or shutting down the output. return -1; } + case NEED_UNWRAP: + { + // We expected to read more, but we got closed. + // Return -1 to indicate to the application to drive the close. + return -1; + } default: { throw new IllegalStateException(); @@ -594,6 +625,13 @@ public class SslConnection extends AbstractConnection case NEED_TASK: { _sslEngine.getDelegatedTask().run(); + if(_peeking) + { + _sslEngine = _sslFactory.restartSSL(_sslEngine.getHandshakeSession()); + _encryptedInput.position(0); + _peeking = false; + continue decryption; + } continue; } case NEED_WRAP: @@ -640,7 +678,7 @@ public class SslConnection extends AbstractConnection } catch (Exception e) { - getEndPoint().close(); + close(); throw e; } finally @@ -710,24 +748,26 @@ public class SslConnection extends AbstractConnection // We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer BufferUtil.compact(_encryptedOutput); int pos = BufferUtil.flipToFill(_encryptedOutput); - SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput); + SSLEngineResult wrapResult; + try + { + wrapResult=_sslEngine.wrap(appOuts, _encryptedOutput); + } + finally + { + BufferUtil.flipToFlush(_encryptedOutput, pos); + } + if (DEBUG) LOG.debug("{} wrap {}", SslConnection.this, wrapResult); - BufferUtil.flipToFlush(_encryptedOutput, pos); if (wrapResult.bytesConsumed()>0) consumed+=wrapResult.bytesConsumed(); + Status wrapResultStatus = wrapResult.getStatus(); boolean allConsumed=true; - // clear empty buffers to prevent position creeping up the buffer for (ByteBuffer b : appOuts) - { - if (BufferUtil.isEmpty(b)) - BufferUtil.clear(b); - else + if (BufferUtil.hasContent(b)) allConsumed=false; - } - - Status wrapResultStatus = wrapResult.getStatus(); // and deal with the results returned from the sslEngineWrap switch (wrapResultStatus) @@ -774,19 +814,26 @@ public class SslConnection extends AbstractConnection { if (DEBUG) LOG.debug("{} renegotiation denied", SslConnection.this); - shutdownOutput(); + getEndPoint().shutdownOutput(); return allConsumed; } // if we have net bytes, let's try to flush them if (BufferUtil.hasContent(_encryptedOutput)) - getEndPoint().flush(_encryptedOutput); + if (!getEndPoint().flush(_encryptedOutput)) + getEndPoint().flush(_encryptedOutput); // one retry // But we also might have more to do for the handshaking state. switch (handshakeStatus) { case NOT_HANDSHAKING: - // Return with the number of bytes consumed (which may be 0) + // If we have not consumed all and had just finished handshaking, then we may + // have just flushed the last handshake in the encrypted buffers, so we should + // try again. + if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput)) + continue; + + // Return true if we consumed all the bytes and encrypted are all flushed return allConsumed && BufferUtil.isEmpty(_encryptedOutput); case NEED_TASK: @@ -818,11 +865,6 @@ public class SslConnection extends AbstractConnection } } } - catch (Exception e) - { - getEndPoint().close(); - throw e; - } finally { if (DEBUG)