Reduce memory usage of SslHandler when OpenSslEngine is in use
Motivation: JDK's SSLEngine.wrap() requires the output buffer to be always as large as MAX_ENCRYPTED_PACKET_LENGTH even if the input buffer contains small number of bytes. Our OpenSslEngine implementation does not have such wasteful behaviot. Modifications: If the current SSLEngine is OpenSslEngine, allocate as much as only needed. Result: Less peak memory usage.
This commit is contained in:
parent
ef59c4ce61
commit
ae61b12b9e
@ -66,6 +66,8 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
// Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
|
// Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
|
||||||
static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
|
static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
|
||||||
|
|
||||||
|
static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH;
|
||||||
|
|
||||||
private static final AtomicIntegerFieldUpdater<OpenSslEngine> DESTROYED_UPDATER =
|
private static final AtomicIntegerFieldUpdater<OpenSslEngine> DESTROYED_UPDATER =
|
||||||
AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
||||||
|
|
||||||
|
@ -180,6 +180,14 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
private final SSLEngine engine;
|
private final SSLEngine engine;
|
||||||
private final int maxPacketBufferSize;
|
private final int maxPacketBufferSize;
|
||||||
private final Executor delegatedTaskExecutor;
|
private final Executor delegatedTaskExecutor;
|
||||||
|
/**
|
||||||
|
* {@code true} if and only if {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} requires the output buffer
|
||||||
|
* to be always as large as {@link #maxPacketBufferSize} even if the input buffer contains small amount of data.
|
||||||
|
* <p>
|
||||||
|
* If this flag is {@code false}, we allocate a smaller output buffer.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private final boolean needsLargeOutNetBuf;
|
||||||
|
|
||||||
private final boolean startTls;
|
private final boolean startTls;
|
||||||
private boolean sentFirstMessage;
|
private boolean sentFirstMessage;
|
||||||
@ -243,6 +251,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
this.delegatedTaskExecutor = delegatedTaskExecutor;
|
this.delegatedTaskExecutor = delegatedTaskExecutor;
|
||||||
this.startTls = startTls;
|
this.startTls = startTls;
|
||||||
maxPacketBufferSize = engine.getSession().getPacketBufferSize();
|
maxPacketBufferSize = engine.getSession().getPacketBufferSize();
|
||||||
|
needsLargeOutNetBuf = !(engine instanceof OpenSslEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getHandshakeTimeoutMillis() {
|
public long getHandshakeTimeoutMillis() {
|
||||||
@ -426,16 +435,18 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
if (pending == null) {
|
if (pending == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (out == null) {
|
|
||||||
out = allocate(ctx, maxPacketBufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pending.msg() instanceof ByteBuf)) {
|
if (!(pending.msg() instanceof ByteBuf)) {
|
||||||
ctx.write(pending.msg(), (ChannelPromise) pending.recycleAndGet());
|
ctx.write(pending.msg(), (ChannelPromise) pending.recycleAndGet());
|
||||||
pendingUnencryptedWrites.remove();
|
pendingUnencryptedWrites.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuf buf = (ByteBuf) pending.msg();
|
ByteBuf buf = (ByteBuf) pending.msg();
|
||||||
|
if (out == null) {
|
||||||
|
out = allocateOutNetBuf(ctx, buf.readableBytes());
|
||||||
|
}
|
||||||
|
|
||||||
SSLEngineResult result = wrap(engine, buf, out);
|
SSLEngineResult result = wrap(engine, buf, out);
|
||||||
|
|
||||||
if (!buf.isReadable()) {
|
if (!buf.isReadable()) {
|
||||||
@ -513,7 +524,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
try {
|
try {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out = allocate(ctx, maxPacketBufferSize);
|
out = allocateOutNetBuf(ctx, 0);
|
||||||
}
|
}
|
||||||
SSLEngineResult result = wrap(engine, Unpooled.EMPTY_BUFFER, out);
|
SSLEngineResult result = wrap(engine, Unpooled.EMPTY_BUFFER, out);
|
||||||
|
|
||||||
@ -1228,6 +1239,20 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates an outbound network buffer for {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} which can encrypt
|
||||||
|
* the specified amount of pending bytes.
|
||||||
|
*/
|
||||||
|
private ByteBuf allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes) {
|
||||||
|
if (needsLargeOutNetBuf) {
|
||||||
|
return allocate(ctx, maxPacketBufferSize);
|
||||||
|
} else {
|
||||||
|
return allocate(ctx, Math.min(
|
||||||
|
pendingBytes + OpenSslEngine.MAX_ENCRYPTION_OVERHEAD_LENGTH,
|
||||||
|
maxPacketBufferSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class LazyChannelPromise extends DefaultPromise<Channel> {
|
private final class LazyChannelPromise extends DefaultPromise<Channel> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user