diff -r -c -N ../Ice-3.5.1.orig/java/src/IceInternal/ThreadPoolWorkQueue.java ./java/src/IceInternal/ThreadPoolWorkQueue.java *** ../Ice-3.5.1.orig/java/src/IceInternal/ThreadPoolWorkQueue.java 2013-10-04 13:18:15.000000000 -0230 --- ./java/src/IceInternal/ThreadPoolWorkQueue.java 2014-11-14 16:23:32.000000000 -0330 *************** *** 89,118 **** throw new Ice.CommunicatorDestroyedException(); } _workItems.add(item); ! postMessage(); } public void message(ThreadPoolCurrent current) { - java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(1); - try - { - buf.rewind(); - int ret = _fdIntrRead.read(buf); - assert(ret > 0); - } - catch(java.io.IOException ex) - { - throw new Ice.SocketException(ex); - } - ThreadPoolWorkItem workItem = null; synchronized(this) { if(!_workItems.isEmpty()) { workItem = _workItems.removeFirst(); } else { --- 89,123 ---- throw new Ice.CommunicatorDestroyedException(); } _workItems.add(item); ! if(_workItems.size() == 1) ! { ! postMessage(); ! } } public void message(ThreadPoolCurrent current) { ThreadPoolWorkItem workItem = null; synchronized(this) { if(!_workItems.isEmpty()) { workItem = _workItems.removeFirst(); + if(_workItems.isEmpty()) + { + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(1); + try + { + buf.rewind(); + int ret = _fdIntrRead.read(buf); + assert(ret > 0); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } } else { diff -r -c -N ../Ice-3.5.1.orig/java/src/IceSSL/TransceiverI.java ./java/src/IceSSL/TransceiverI.java *** ../Ice-3.5.1.orig/java/src/IceSSL/TransceiverI.java 2013-10-04 13:18:15.000000000 -0230 --- ./java/src/IceSSL/TransceiverI.java 2014-11-14 16:23:32.000000000 -0330 *************** *** 297,328 **** _netInput.flip(); SSLEngineResult result = _engine.unwrap(_netInput, _appInput); _netInput.compact(); ! switch(result.getStatus()) ! { ! case BUFFER_OVERFLOW: { ! assert(false); ! break; } ! case BUFFER_UNDERFLOW: { ! int status = readNonBlocking(); ! if(status != IceInternal.SocketOperation.None) { - assert(status == IceInternal.SocketOperation.Read); return false; } continue; } - case CLOSED: - { - throw new Ice.ConnectionLostException(); - } - case OK: - { - break; - } - } pos = buf.b.position(); fill(buf.b); --- 297,318 ---- _netInput.flip(); SSLEngineResult result = _engine.unwrap(_netInput, _appInput); _netInput.compact(); ! ! Status status = result.getStatus(); ! if(status == Status.CLOSED) { ! throw new Ice.ConnectionLostException(); } ! // Android API 21 SSLEngine doesn't report underflow, so look at the absence of ! // network data and application data to signal a network read. ! else if(status == Status.BUFFER_UNDERFLOW || (_appInput.position() == 0 && _netInput.position() == 0)) { ! if(readNonBlocking() == IceInternal.SocketOperation.Read) { return false; } continue; } pos = buf.b.position(); fill(buf.b); *************** *** 338,353 **** _stats.bytesReceived(type(), buf.b.position() - pos); } } } catch(SSLException ex) { throw new Ice.SecurityException("IceSSL: error during read", ex); } // // Return a boolean to indicate whether more data is available. // ! moreData.value = _netInput.position() > 0; return true; } --- 328,357 ---- _stats.bytesReceived(type(), buf.b.position() - pos); } } + + // If there is no more application data, do one further read to ensure + // that the SSLEngine has no buffered data (Android R21 and greater only). + if(_appInput.position() == 0) + { + _netInput.flip(); + _engine.unwrap(_netInput, _appInput); + _netInput.compact(); + + // Don't check the status here since we may have already filled + // the buffer with a complete request which must be processed. + } } catch(SSLException ex) { throw new Ice.SecurityException("IceSSL: error during read", ex); } + // // Return a boolean to indicate whether more data is available. // ! moreData.value = _netInput.position() > 0 || _appInput.position() > 0; ! return true; } *************** *** 534,539 **** --- 538,548 ---- } case NEED_UNWRAP: { + if(_netInput.position() == 0 && readNonBlocking() == IceInternal.SocketOperation.Read) + { + return IceInternal.SocketOperation.Read; + } + // // The engine needs more data. We might already have enough data in // the _netInput buffer to satisfy the engine. If not, the engine *************** *** 867,875 **** // Copy directly into the destination buffer's backing array. // byte[] arr = buf.array(); ! int offset = buf.arrayOffset() + buf.position(); ! _appInput.get(arr, offset, bytesAvailable); ! buf.position(offset + bytesAvailable); } else if(_appInput.hasArray()) { --- 876,883 ---- // Copy directly into the destination buffer's backing array. // byte[] arr = buf.array(); ! _appInput.get(arr, buf.arrayOffset() + buf.position(), bytesAvailable); ! buf.position(buf.position() + bytesAvailable); } else if(_appInput.hasArray()) { *************** *** 877,885 **** // Copy directly from the source buffer's backing array. // byte[] arr = _appInput.array(); ! int offset = _appInput.arrayOffset() + _appInput.position(); ! buf.put(arr, offset, bytesAvailable); ! _appInput.position(offset + bytesAvailable); } else { --- 885,892 ---- // Copy directly from the source buffer's backing array. // byte[] arr = _appInput.array(); ! buf.put(arr, _appInput.arrayOffset() + _appInput.position(), bytesAvailable); ! _appInput.position(_appInput.position() + bytesAvailable); } else {