Only do priming read if there is no space in dsts buffers.
Motivation: A SSL_read is needed to ensure the bio buffer is flushed, for this we did a priming read. This can be removed in many cases. Also ensure we always fill as much as possible in the destination buffers. Modifications: - Only do priming read if capacity of all dsts buffers is zero - Always produce as must data as possible in the dsts buffers. Result: Faster code.
This commit is contained in:
parent
7bc07350f1
commit
d345465bba
@ -598,7 +598,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
"offset: " + dstsOffset + ", length: " + dstsLength +
|
"offset: " + dstsOffset + ", length: " + dstsLength +
|
||||||
" (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
|
" (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
|
||||||
}
|
}
|
||||||
int capacity = 0;
|
long capacity = 0;
|
||||||
final int endOffset = dstsOffset + dstsLength;
|
final int endOffset = dstsOffset + dstsLength;
|
||||||
for (int i = dstsOffset; i < endOffset; i ++) {
|
for (int i = dstsOffset; i < endOffset; i ++) {
|
||||||
ByteBuffer dst = dsts[i];
|
ByteBuffer dst = dsts[i];
|
||||||
@ -628,7 +628,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int srcsEndOffset = srcsOffset + srcsLength;
|
final int srcsEndOffset = srcsOffset + srcsLength;
|
||||||
int len = 0;
|
long len = 0;
|
||||||
for (int i = srcsOffset; i < srcsEndOffset; i++) {
|
for (int i = srcsOffset; i < srcsEndOffset; i++) {
|
||||||
ByteBuffer src = srcs[i];
|
ByteBuffer src = srcs[i];
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
@ -679,56 +679,14 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (srcsOffset < srcsEndOffset);
|
} while (srcsOffset < srcsEndOffset);
|
||||||
|
|
||||||
int lastPrimingReadResult = SSL.readFromSSL(ssl, EMPTY_ADDR, 0); // priming read
|
|
||||||
|
|
||||||
// check if SSL_read returned <= 0. In this case we need to check the error and see if it was something
|
|
||||||
// fatal.
|
|
||||||
if (lastPrimingReadResult <= 0) {
|
|
||||||
int sslError = SSL.getError(ssl, lastPrimingReadResult);
|
|
||||||
switch (sslError) {
|
|
||||||
case SSL.SSL_ERROR_NONE:
|
|
||||||
case SSL.SSL_ERROR_WANT_ACCEPT:
|
|
||||||
case SSL.SSL_ERROR_WANT_CONNECT:
|
|
||||||
case SSL.SSL_ERROR_WANT_WRITE:
|
|
||||||
case SSL.SSL_ERROR_WANT_READ:
|
|
||||||
case SSL.SSL_ERROR_WANT_X509_LOOKUP:
|
|
||||||
case SSL.SSL_ERROR_ZERO_RETURN:
|
|
||||||
// Nothing to do here
|
|
||||||
break;
|
|
||||||
case SSL.SSL_ERROR_SSL:
|
|
||||||
case SSL.SSL_ERROR_SYSCALL:
|
|
||||||
int err = SSL.getLastErrorNumber();
|
|
||||||
if (OpenSsl.isError(err)) {
|
|
||||||
shutdownWithError("SSL_read", SSL.getErrorString(err));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// fall-through
|
|
||||||
default:
|
|
||||||
// Clear the error queue
|
|
||||||
SSL.clearError();
|
|
||||||
|
|
||||||
checkPendingHandshakeException();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rejectRemoteInitiatedRenegation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There won't be any application data until we're done handshaking
|
rejectRemoteInitiatedRenegation();
|
||||||
//
|
|
||||||
// We first check handshakeFinished to eliminate the overhead of extra JNI call if possible.
|
// Number of produced bytes
|
||||||
int pendingApp = handshakeState == HandshakeState.FINISHED ? SSL.pendingReadableBytesInSSL(ssl) : 0;
|
|
||||||
int bytesProduced = 0;
|
int bytesProduced = 0;
|
||||||
|
|
||||||
if (pendingApp > 0) {
|
if (capacity > 0) {
|
||||||
// Do we have enough room in dsts to write decrypted data?
|
|
||||||
if (capacity < pendingApp) {
|
|
||||||
return new SSLEngineResult(
|
|
||||||
BUFFER_OVERFLOW, mayFinishHandshake(getHandshakeStatus()), bytesConsumed, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write decrypted data to dsts buffers
|
// Write decrypted data to dsts buffers
|
||||||
int idx = dstsOffset;
|
int idx = dstsOffset;
|
||||||
while (idx < endOffset) {
|
while (idx < endOffset) {
|
||||||
@ -738,20 +696,20 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingApp <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bytesRead = readPlaintextData(dst);
|
int bytesRead = readPlaintextData(dst);
|
||||||
|
|
||||||
|
// TODO: We may want to consider if we move this check and only do it in a less often called place at
|
||||||
|
// the price of not being 100% accurate, like for example when calling SSL.getError(...).
|
||||||
rejectRemoteInitiatedRenegation();
|
rejectRemoteInitiatedRenegation();
|
||||||
|
|
||||||
if (bytesRead > 0) {
|
if (bytesRead > 0) {
|
||||||
bytesProduced += bytesRead;
|
bytesProduced += bytesRead;
|
||||||
pendingApp -= bytesRead;
|
|
||||||
|
|
||||||
if (!dst.hasRemaining()) {
|
if (!dst.hasRemaining()) {
|
||||||
idx ++;
|
idx ++;
|
||||||
|
} else {
|
||||||
|
// We read everything return now.
|
||||||
|
return newResult(bytesConsumed, bytesProduced);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int sslError = SSL.getError(ssl, bytesRead);
|
int sslError = SSL.getError(ssl, bytesRead);
|
||||||
@ -772,9 +730,24 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If the capacity of all destination buffers is 0 we need to trigger a SSL_read anyway to ensure
|
||||||
|
// everything is flushed in the BIO pair and so we can detect it in the pendingAppData() call.
|
||||||
|
if (SSL.readFromSSL(ssl, EMPTY_ADDR, 0) <= 0) {
|
||||||
|
// We do not check SSL_get_error as we are not interested in any error that is not fatal.
|
||||||
|
int err = SSL.getLastErrorNumber();
|
||||||
|
if (OpenSsl.isError(err)) {
|
||||||
|
shutdownWithError("SSL_read", SSL.getErrorString(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pendingAppData() > 0) {
|
||||||
|
// We filled all buffers but there is still some data pending in the BIO buffer, return BUFFER_OVERFLOW.
|
||||||
|
return new SSLEngineResult(
|
||||||
|
BUFFER_OVERFLOW, mayFinishHandshake(getHandshakeStatus()), bytesConsumed, bytesProduced);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if we received a close_notify message from the peer
|
// Check to see if we received a close_notify message from the peer.
|
||||||
if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
|
if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
|
||||||
closeAll();
|
closeAll();
|
||||||
}
|
}
|
||||||
@ -782,6 +755,12 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
return newResult(bytesConsumed, bytesProduced);
|
return newResult(bytesConsumed, bytesProduced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int pendingAppData() {
|
||||||
|
// There won't be any application data until we're done handshaking.
|
||||||
|
// We first check handshakeFinished to eliminate the overhead of extra JNI call if possible.
|
||||||
|
return handshakeState == HandshakeState.FINISHED ? SSL.pendingReadableBytesInSSL(ssl) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
private SSLEngineResult newResult(int bytesConsumed, int bytesProduced) throws SSLException {
|
private SSLEngineResult newResult(int bytesConsumed, int bytesProduced) throws SSLException {
|
||||||
return new SSLEngineResult(
|
return new SSLEngineResult(
|
||||||
getEngineStatus(), mayFinishHandshake(getHandshakeStatus()), bytesConsumed, bytesProduced);
|
getEngineStatus(), mayFinishHandshake(getHandshakeStatus()), bytesConsumed, bytesProduced);
|
||||||
|
Loading…
Reference in New Issue
Block a user