at.yawk.dbus.protocol.codec.MessageHeaderCodec Maven / Gradle / Ivy
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package at.yawk.dbus.protocol.codec;
import at.yawk.dbus.protocol.HeaderField;
import at.yawk.dbus.protocol.MessageHeader;
import at.yawk.dbus.protocol.MessageType;
import at.yawk.dbus.protocol.object.*;
import at.yawk.dbus.protocol.type.ArrayTypeDefinition;
import at.yawk.dbus.protocol.type.BasicType;
import at.yawk.dbus.protocol.type.StructTypeDefinition;
import at.yawk.dbus.protocol.type.TypeDefinition;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.DecoderException;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
/**
* @author yawkat
*/
@Slf4j
class MessageHeaderCodec extends ByteToMessageCodec {
// the headers are an array of byte:variant structs
private static final StructTypeDefinition HEADER_FIELD_TYPE =
new StructTypeDefinition(Arrays.asList(BasicType.BYTE, BasicType.VARIANT));
private static final ArrayTypeDefinition HEADER_FIELD_LIST_TYPE = new ArrayTypeDefinition(HEADER_FIELD_TYPE);
private static final int MIN_HEADER_LENGTH =
12 + // static header
4 // 0 array length
;
private static final byte PROTOCOL_VERSION = 1;
// flags
private static final byte NO_REPLY_EXPECTED = 0x1;
private static final byte NO_AUTO_START = 0x2;
private static final byte ALLOW_INTERACTIVE_AUTHORIZATION = 0x4;
/**
* How many bytes still need to be read in the current packet.
*/
private int toRead;
/**
* Byte order to forward to the next decoders.
*/
private ByteOrder byteOrder;
@Override
protected void encode(ChannelHandlerContext ctx, MessageHeader msg, ByteBuf out)
throws Exception {
out = out.order(Local.OUTBOUND_ORDER);
AlignableByteBuf alignedBuf = AlignableByteBuf.encoding(out);
out.writeByte(Local.OUTBOUND_ORDER == ByteOrder.LITTLE_ENDIAN ? 'l' : 'B');
out.writeByte(msg.getMessageType().getId());
byte flags = 0;
if (msg.isNoReplyExpected()) { flags |= NO_REPLY_EXPECTED; }
if (msg.isNoAutoStart()) { flags |= NO_AUTO_START; }
if (msg.isAllowInteractiveAuthorization()) { flags |= ALLOW_INTERACTIVE_AUTHORIZATION; }
out.writeByte(flags);
byte protocolVersion = msg.getMajorProtocolVersion();
if (protocolVersion == 0) { protocolVersion = PROTOCOL_VERSION; }
out.writeByte(protocolVersion);
out.writeInt((int) msg.getMessageBodyLength());
int serial = msg.getSerial();
if (serial == 0) { serial = Local.generateSerial(ctx); }
out.writeInt(serial);
checkRequiredHeaderFieldsPresent(msg);
ArrayObject headerObject = ArrayObject.create(
HEADER_FIELD_LIST_TYPE,
msg.getHeaderFields().entrySet().stream()
.map(entry -> {
BasicObject id = BasicObject.createByte(entry.getKey().getId());
DbusObject value = entry.getValue();
return StructObject.create(
HEADER_FIELD_TYPE,
Arrays.asList(id, VariantObject.create(value))
);
})
.collect(Collectors.toList())
);
headerObject.serialize(alignedBuf);
alignedBuf.alignWrite(8);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf rawBuf, List