Schannel: Send more than one message at a time
By encrypting multiple 'Messages' before we send them we reduce the overhead on both ourselves and the receiving end. This brings some synthetic benchmark I have written from taking around 50-60+ seconds to around 10. With OpenSSL it is taking around 2 seconds, so there is still some headroom, but this should be okay for now. Change-Id: Ibcbc04a503a4b49197296ceaea2f0c38f528dfc4 Reviewed-by: Mate Barany <mate.barany@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
b4b90bfbaf
commit
4e60a6b556
@ -1765,23 +1765,41 @@ auto TlsCryptographSchannel::getNextEncryptedMessage() -> MessageBufferResult
|
|||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
auto &writeBuffer = d->tlsWriteBuffer();
|
auto &writeBuffer = d->tlsWriteBuffer();
|
||||||
|
|
||||||
|
auto allocateMessage = [&fullMessage](qsizetype size) -> QSpan<char> {
|
||||||
|
auto targetSize = fullMessage.size() + size;
|
||||||
|
if (fullMessage.capacity() < targetSize) {
|
||||||
|
qsizetype newSize = fullMessage.capacity() * 2;
|
||||||
|
if (newSize < targetSize)
|
||||||
|
newSize = targetSize;
|
||||||
|
fullMessage.reserve(newSize);
|
||||||
|
}
|
||||||
|
fullMessage.resizeForOverwrite(targetSize);
|
||||||
|
return QSpan(fullMessage).subspan(fullMessage.size() - size);
|
||||||
|
};
|
||||||
|
|
||||||
const int headerSize = int(streamSizes.cbHeader);
|
const int headerSize = int(streamSizes.cbHeader);
|
||||||
const int trailerSize = int(streamSizes.cbTrailer);
|
const int trailerSize = int(streamSizes.cbTrailer);
|
||||||
|
constexpr qsizetype MessageBufferThreshold = 128 * 1024;
|
||||||
|
|
||||||
|
qint64 writeBufferSize = 0;
|
||||||
|
while ((writeBufferSize = writeBuffer.size()) > 0
|
||||||
|
&& fullMessage.size() < MessageBufferThreshold) {
|
||||||
// Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
|
// Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
|
||||||
const int size = int(std::min(writeBuffer.size(), qint64(streamSizes.cbMaximumMessage)));
|
const int bodySize = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
|
||||||
fullMessage.resizeForOverwrite(headerSize + trailerSize + size);
|
auto messageSize = headerSize + bodySize + trailerSize;
|
||||||
char *header = fullMessage.data();
|
QSpan buffer = allocateMessage(messageSize);
|
||||||
|
char *header = buffer.data();
|
||||||
char *body = header + headerSize;
|
char *body = header + headerSize;
|
||||||
char *trailer = body + size;
|
char *trailer = body + bodySize;
|
||||||
{
|
{
|
||||||
// Use peek() here instead of read() so we don't lose data if encryption fails.
|
// Use peek() here instead of read() so we don't lose data if encryption fails.
|
||||||
qint64 copied = writeBuffer.peek(body, size);
|
qint64 copied = writeBuffer.peek(body, bodySize);
|
||||||
Q_ASSERT(copied == size);
|
Q_ASSERT(copied == bodySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecBuffer inputBuffers[] = {
|
SecBuffer inputBuffers[] = {
|
||||||
createSecBuffer(header, headerSize, SECBUFFER_STREAM_HEADER),
|
createSecBuffer(header, headerSize, SECBUFFER_STREAM_HEADER),
|
||||||
createSecBuffer(body, size, SECBUFFER_DATA),
|
createSecBuffer(body, bodySize, SECBUFFER_DATA),
|
||||||
createSecBuffer(trailer, trailerSize, SECBUFFER_STREAM_TRAILER),
|
createSecBuffer(trailer, trailerSize, SECBUFFER_STREAM_TRAILER),
|
||||||
createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
|
createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
|
||||||
};
|
};
|
||||||
@ -1790,6 +1808,7 @@ auto TlsCryptographSchannel::getNextEncryptedMessage() -> MessageBufferResult
|
|||||||
ARRAYSIZE(inputBuffers),
|
ARRAYSIZE(inputBuffers),
|
||||||
inputBuffers
|
inputBuffers
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto status = EncryptMessage(&contextHandle, 0, &message, 0); status != SEC_E_OK) {
|
if (auto status = EncryptMessage(&contextHandle, 0, &message, 0); status != SEC_E_OK) {
|
||||||
setErrorAndEmit(d, QAbstractSocket::SslInternalError,
|
setErrorAndEmit(d, QAbstractSocket::SslInternalError,
|
||||||
QSslSocket::tr("Schannel failed to encrypt data: %1")
|
QSslSocket::tr("Schannel failed to encrypt data: %1")
|
||||||
@ -1797,11 +1816,13 @@ auto TlsCryptographSchannel::getNextEncryptedMessage() -> MessageBufferResult
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Data was encrypted successfully, so we free() what we peek()ed earlier
|
// Data was encrypted successfully, so we free() what we peek()ed earlier
|
||||||
writeBuffer.free(size);
|
writeBuffer.free(bodySize);
|
||||||
|
|
||||||
// The trailer's size is not final, so resize fullMessage to not send trailing junk
|
// The trailer's size is not final, so resize fullMessage to not send trailing junk
|
||||||
fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer
|
auto finalSize = qsizetype(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer
|
||||||
+ inputBuffers[2].cbBuffer);
|
+ inputBuffers[2].cbBuffer);
|
||||||
|
fullMessage.chop(messageSize - finalSize);
|
||||||
|
}
|
||||||
result.ok = true;
|
result.ok = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user