/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltcore.network;
import java.util.List;
import com.google_voltpatches.common.collect.ImmutableList;
import io.netty_voltpatches.buffer.ByteBuf;
/**
* Container and tracking class used during message encryptions
*/
class EncryptFrame {
final static int UNCHUNKED_SIGIL = -1;
/**
* chunk number in a sequence of chunks. If a message is split into 3 chunks
* then their respective chunk numbers would be 1, 2, and 3. Each chunk
* chunks value would be 3
*/
final int chunkno;
/**
* chunk number in a sequence of chunks. If a message is split into 3 chunks
* then their respective chunk numbers would be 1, 2, and 3. Each chunk
* chunks value would be 3
*/
final int chunks;
/**
* Once encrypted this value signifies the difference in bytes between
* the encrypted chunk, and the non encrypted source
*/
final int delta;
/**
* SSLEngine encrypt can only encrypt up to 16k at a time, so a frame
* contains an encrypt operation source buffer which is a slice window
* into the underlying bb buffer
*/
final ByteBuf frame;
final ByteBuf bb;
/**
* Indicates how many Volt messages this frame contains
*/
final int msgs;
EncryptFrame(ByteBuf source, int msgs) {
this(1, 1, UNCHUNKED_SIGIL, msgs, source, source);
}
EncryptFrame(ByteBuf source, int delta, int msgs) {
this(1, 1, delta, msgs, source, source);
}
public boolean isChunked() {
return delta != UNCHUNKED_SIGIL;
}
public boolean inEncrypted() {
return bb == null;
}
public boolean isLast() {
return isChunked() && chunkno == chunks;
}
List<EncryptFrame> chunked(final int frameMax) {
if (!bb.isReadable()) {
return ImmutableList.of();
}
if (bb.readableBytes() <= frameMax) {
return ImmutableList.of(new EncryptFrame(1, 1, 0, msgs, bb, bb));
}
int frames = bb.writerIndex() / frameMax;
frames = bb.writerIndex() % frameMax == 0 ? frames : frames+1;
ImmutableList.Builder<EncryptFrame> lbld = ImmutableList.builder();
for (int chunk = 1; chunk <= frames; ++chunk) {
int sliceSz = Math.min(frameMax, bb.readableBytes());
// slices are views into the underlying byte buf (bb)
EncryptFrame piece = new EncryptFrame(chunk, frames, 0, msgs, bb.readSlice(sliceSz), bb);
lbld.add(piece);
}
return lbld.build();
}
EncryptFrame encrypted(int delta, ByteBuf encrypted) {
return new EncryptFrame(chunkno, chunks, delta, msgs, encrypted, null);
}
private EncryptFrame(int chunkno, int chunks, int delta, int msgs, ByteBuf frame, ByteBuf sliceSource) {
this.chunkno = chunkno;
this.chunks = chunks;
this.delta = delta;
this.frame = frame;
this.bb = sliceSource;
this.msgs = msgs;
}
@Override
public String toString() {
return "EncryptFrame [chunkno=" + chunkno + ", chunks=" + chunks
+ ", msgs=" + msgs + ", delta=" + delta + ", slice=" + frame + "]";
}
}