From 4c210fc38d047fc825eb826289f6e67a98269abc Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 19 Jan 2017 17:13:13 +0100 Subject: [PATCH] Initial MQTT packet structure. issue 73 --- .../net/mqtt/packet/MqttPacketConnect.java | 71 +++++++++++++++++++ .../net/mqtt/packet/MqttPacketConnectAck.java | 29 ++++++++ .../net/mqtt/packet/MqttPacketDisconnect.java | 14 ++++ .../net/mqtt/packet/MqttPacketHeader.java | 36 ++++++++++ .../net/mqtt/packet/MqttPacketPingReq.java | 13 ++++ .../net/mqtt/packet/MqttPacketPingResp.java | 14 ++++ .../net/mqtt/packet/MqttPacketPublish.java | 39 ++++++++++ .../net/mqtt/packet/MqttPacketPublishAck.java | 18 +++++ .../mqtt/packet/MqttPacketPublishComp.java | 20 ++++++ .../net/mqtt/packet/MqttPacketPublishRec.java | 20 ++++++ .../net/mqtt/packet/MqttPacketPublishRel.java | 20 ++++++ .../net/mqtt/packet/MqttPacketSubscribe.java | 39 ++++++++++ .../mqtt/packet/MqttPacketSubscribeAck.java | 36 ++++++++++ .../mqtt/packet/MqttPacketUnsubscribe.java | 35 +++++++++ .../mqtt/packet/MqttPacketUnsubscribeAck.java | 20 ++++++ .../packet/MqttVariableIntSerializer.java | 43 +++++++++++ src/zutil/parser/binary/BinaryFieldData.java | 2 +- src/zutil/parser/binary/BinaryStruct.java | 11 ++- .../mqtt/packet/MqttPacketConnectTest.java | 65 +++++++++++++++++ 19 files changed, 541 insertions(+), 4 deletions(-) create mode 100755 src/zutil/net/mqtt/packet/MqttPacketConnect.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketConnectAck.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketDisconnect.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketHeader.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPingReq.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPingResp.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPublish.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPublishAck.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPublishComp.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPublishRec.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketPublishRel.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketSubscribe.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketSubscribeAck.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketUnsubscribe.java create mode 100755 src/zutil/net/mqtt/packet/MqttPacketUnsubscribeAck.java create mode 100755 src/zutil/net/mqtt/packet/MqttVariableIntSerializer.java create mode 100755 test/zutil/net/mqtt/packet/MqttPacketConnectTest.java diff --git a/src/zutil/net/mqtt/packet/MqttPacketConnect.java b/src/zutil/net/mqtt/packet/MqttPacketConnect.java new file mode 100755 index 0000000..53e6c17 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketConnect.java @@ -0,0 +1,71 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * This packet is the first message sent from a Client when it + * has established a connection to a Server. A Client can only + * send the CONNECT Packet once over a Network Connection. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketConnect implements BinaryStruct { + + // Variable header + + @BinaryField(index = 2001, length = 16) + private int protocolNameLength = 4; + /** + * The Protocol Name is a UTF-8 encoded string that represents + * the protocol name “MQTT”, capitalized as shown. The string, + * its offset and length will not be changed by future versions + * of the MQTT specification. + */ + @BinaryField(index = 2002, length = 8*4) + public String protocolName = "MQTT"; + + /** + * The value represents the revision level of the protocol used by + * the Client. The value of the Protocol Level field for the version + * 3.1.1 of the protocol is 4 (0x04) + */ + @BinaryField(index = 2003, length = 8) + public int protocolLevel = 0x04; + + + /** Indicates that the payload contains a username */ + @BinaryField(index = 2010, length = 1) + public boolean flagUsername; + /** Indicates that the payload contains a password */ + @BinaryField(index = 2011, length = 1) + public boolean flagPassword; + /** Specifies if the Will Message is to be Retained when it is published. */ + @BinaryField(index = 2012, length = 1) + public boolean flagWillRetain; + /** Specifies the QoS level to be used when publishing the Will Message. */ + @BinaryField(index = 2013, length = 2) + public int flagWillQoS; + @BinaryField(index = 2014, length = 1) + public boolean flagWillFlag; + @BinaryField(index = 2015, length = 1) + /** This bit specifies the handling of the Session state. */ + public boolean flagCleanSession; + @BinaryField(index = 2016, length = 1) + private boolean reserved; + + + /** + * The Keep Alive is a time interval measured in seconds and + * it is the maximum time interval that is permitted to elapse + * between the point at which the Client finishes transmitting one + * Control Packet and the point it starts sending the next. + * A Keep Alive value of zero (0) has the effect of turning off + * the keep alive mechanism. + */ + @BinaryField(index = 2020, length = 16) + public int keepAlive; + + + // Payload + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketConnectAck.java b/src/zutil/net/mqtt/packet/MqttPacketConnectAck.java new file mode 100755 index 0000000..8712899 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketConnectAck.java @@ -0,0 +1,29 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * The CONNACK Packet is the packet sent by the Server in response to a + * CONNECT Packet received from a Client. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketConnectAck implements BinaryStruct{ + public static final int RETCODE_OK = 0; + public static final int RETCODE_PROT_VER_ERROR = 1; + public static final int RETCODE_IDENTIFIER_REJECT = 2; + public static final int RETCODE_SERVER_UNAVAILABLE = 3; + public static final int RETCODE_BADD_USER_OR_PASS = 4; + public static final int RETCODE_NOT_AUTHORIZED = 5; + + + @BinaryField(index = 2000, length = 7) + private int flagReserved; + /** Indicates that there is a valid Session available */ + @BinaryField(index = 2001, length = 1) + public int flagSessionPresent; + + @BinaryField(index = 2002, length = 8) + public int returnCode; + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketDisconnect.java b/src/zutil/net/mqtt/packet/MqttPacketDisconnect.java new file mode 100755 index 0000000..9779db3 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketDisconnect.java @@ -0,0 +1,14 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * The DISCONNECT Packet is the final Control Packet sent from the Client to + * the Server. It indicates that the Client is disconnecting cleanly. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketDisconnect implements BinaryStruct{ + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketHeader.java b/src/zutil/net/mqtt/packet/MqttPacketHeader.java new file mode 100755 index 0000000..c8f5b69 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketHeader.java @@ -0,0 +1,36 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * + */ +public class MqttPacketHeader implements BinaryStruct { + + // RESERVED = 0; + public static final int PACKET_TYPE_CONNACK = 2; + public static final int PACKET_TYPE_PUBLISH = 3; + public static final int PACKET_TYPE_PUBACK = 4; + public static final int PACKET_TYPE_PUBREC = 5; + public static final int PACKET_TYPE_PUBREL = 6; + public static final int PACKET_TYPE_PUBCOMP = 7; + public static final int PACKET_TYPE_SUBSCRIBE = 8; + public static final int PACKET_TYPE_SUBACK = 9; + public static final int PACKET_TYPE_UNSUBSCRIBE = 10; + public static final int PACKET_TYPE_UNSUBACK = 11; + public static final int PACKET_TYPE_PINGREQ = 12; + public static final int PACKET_TYPE_PINGRESP = 13; + public static final int PACKET_TYPE_DISCONNECT = 14; + // RESERVED = 15 + + + + @BinaryField(index = 1, length = 4) + private byte type; + @BinaryField(index = 2, length = 4) + private byte flags; + + @CustomBinaryField(index = 3, serializer = MqttVariableIntSerializer.class) + private int length; + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPingReq.java b/src/zutil/net/mqtt/packet/MqttPacketPingReq.java new file mode 100755 index 0000000..b55ec47 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPingReq.java @@ -0,0 +1,13 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * The PINGREQ Packet is used in Keep Alive processing + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPingReq implements BinaryStruct{ + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPingResp.java b/src/zutil/net/mqtt/packet/MqttPacketPingResp.java new file mode 100755 index 0000000..9a292b2 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPingResp.java @@ -0,0 +1,14 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * A PINGRESP Packet is sent by the Server to the Client in response to a + * PINGREQ Packet. It indicates that the Server is alive. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPingResp implements BinaryStruct{ + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPublish.java b/src/zutil/net/mqtt/packet/MqttPacketPublish.java new file mode 100755 index 0000000..c059136 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPublish.java @@ -0,0 +1,39 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * A PUBLISH Control Packet is sent from a Client to a Server + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPublish implements BinaryStruct{ + + // Static Header +/* + @BinaryField(index = 2000, length = 1) + private int flagDup; + @BinaryField(index = 2001, length = 2) + private int flagQoS; + @BinaryField(index = 2002, length = 1) + private int flagRetain; + + @CustomBinaryField(index = 3, serializer = MqttVariableIntSerializer.class) + private int length; +*/ + + // Variable Header + + @BinaryField(index = 2101, length = 16) + private int topicNameLength; + /** The Topic Name identifies the information channel to which payload data is published. */ + @VariableLengthBinaryField(index = 2102, lengthField = "topicNameLength") + public String topicName; + + @BinaryField(index = 2102, length = 16) + public int packetId; + + + // Optional Payload + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPublishAck.java b/src/zutil/net/mqtt/packet/MqttPacketPublishAck.java new file mode 100755 index 0000000..0d96072 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPublishAck.java @@ -0,0 +1,18 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * A PUBACK Packet is the response to a PUBLISH Packet with QoS level 1. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPublishAck implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPublishComp.java b/src/zutil/net/mqtt/packet/MqttPacketPublishComp.java new file mode 100755 index 0000000..853bdba --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPublishComp.java @@ -0,0 +1,20 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * Publish complete. + * The PUBCOMP Packet is the response to a PUBREL Packet. It is the fourth and + * final packet of the QoS 2 protocol exchange. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPublishComp implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPublishRec.java b/src/zutil/net/mqtt/packet/MqttPacketPublishRec.java new file mode 100755 index 0000000..ae71d8e --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPublishRec.java @@ -0,0 +1,20 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * Publish received. + * A PUBREC Packet is the response to a PUBLISH Packet with QoS 2. It is the + * second packet of the QoS 2 protocol exchange. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPublishRec implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketPublishRel.java b/src/zutil/net/mqtt/packet/MqttPacketPublishRel.java new file mode 100755 index 0000000..c029316 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketPublishRel.java @@ -0,0 +1,20 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +/** + * Publish release. + * A PUBREL Packet is the response to a PUBREC Packet. It is the third packet + * of the QoS 2 protocol exchange. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketPublishRel implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketSubscribe.java b/src/zutil/net/mqtt/packet/MqttPacketSubscribe.java new file mode 100755 index 0000000..29c73cb --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketSubscribe.java @@ -0,0 +1,39 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +import java.util.List; + +/** + * The SUBSCRIBE Packet is sent from the Client to the Server to create one or more Subscriptions. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketSubscribe implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + // Payload + + public List payload; + + + + + public static class MqttSubscribePayload implements BinaryStruct{ + + @BinaryField(index = 3001, length = 16) + private int topicFilterLength; + /** A filter indicating the Topic to which the Client wants to subscribe to*/ + @VariableLengthBinaryField(index = 3002, lengthField = "topicFilterLength") + public String topicFilter; + + @BinaryField(index = 3003, length = 6) + private int reserved; + @BinaryField(index = 3004, length = 2) + private int qos; + } +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketSubscribeAck.java b/src/zutil/net/mqtt/packet/MqttPacketSubscribeAck.java new file mode 100755 index 0000000..4471980 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketSubscribeAck.java @@ -0,0 +1,36 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +import java.util.List; + +/** + * A SUBACK Packet is sent by the Server to the Client to confirm receipt + * and processing of a SUBSCRIBE Packet. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketSubscribeAck implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + // Payload + + public List payload; + + + + + public static class MqttSubscribeAckPayload implements BinaryStruct{ + public static final int RETCODE_SUCESS_MAX_QOS_0 = 0; + public static final int RETCODE_SUCESS_MAX_QOS_1 = 1; + public static final int RETCODE_SUCESS_MAX_QOS_2 = 2; + public static final int RETCODE_FAILURE = 0x80; + + @BinaryField(index = 3001, length = 8) + public int returnCode; + } +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketUnsubscribe.java b/src/zutil/net/mqtt/packet/MqttPacketUnsubscribe.java new file mode 100755 index 0000000..17036df --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketUnsubscribe.java @@ -0,0 +1,35 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +import java.util.List; + +/** + * An UNSUBSCRIBE Packet is sent by the Client to the Server, to unsubscribe from topics. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketUnsubscribe implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + + // Payload + + public List payload; + + + + + public static class MqttUnsubscribePayload implements BinaryStruct{ + + @BinaryField(index = 3001, length = 16) + private int topicFilterLength; + /** A filter indicating the Topic to which the Client wants to subscribe to*/ + @VariableLengthBinaryField(index = 3002, lengthField = "topicFilterLength") + public String topicFilter; + + } +} diff --git a/src/zutil/net/mqtt/packet/MqttPacketUnsubscribeAck.java b/src/zutil/net/mqtt/packet/MqttPacketUnsubscribeAck.java new file mode 100755 index 0000000..517e459 --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttPacketUnsubscribeAck.java @@ -0,0 +1,20 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryStruct; + +import java.util.List; + +/** + * The UNSUBACK Packet is sent by the Server to the Client to confirm receipt + * of an UNSUBSCRIBE Packet. + * + * @see MQTT v3.1.1 Spec + */ +public class MqttPacketUnsubscribeAck implements BinaryStruct{ + + // Variable Header + + @BinaryField(index = 2000, length = 16) + public int packetId; + +} diff --git a/src/zutil/net/mqtt/packet/MqttVariableIntSerializer.java b/src/zutil/net/mqtt/packet/MqttVariableIntSerializer.java new file mode 100755 index 0000000..a8ae93d --- /dev/null +++ b/src/zutil/net/mqtt/packet/MqttVariableIntSerializer.java @@ -0,0 +1,43 @@ +package zutil.net.mqtt.packet; + +import zutil.parser.binary.BinaryFieldData; +import zutil.parser.binary.BinaryFieldSerializer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Code from MQTT specification + */ +public class MqttVariableIntSerializer implements BinaryFieldSerializer{ + + @Override + public Integer read(InputStream in, BinaryFieldData field) throws IOException { + int multiplier = 1; + int value = 0; + int encodedByte; + do { + encodedByte = in.read(); + value += (encodedByte & 127) * multiplier; + if (multiplier > 128 * 128 * 128) + throw new IOException("Malformed Remaining Length"); + multiplier *= 128; + } while ((encodedByte & 128) != 0); + return value; + } + + @Override + public void write(OutputStream out, Integer obj, BinaryFieldData field) throws IOException { + int x = obj; + int encodedByte; + do { + encodedByte = x % 128; + x = x / 128; + // if there are more data to encode, set the top bit of this byte + if (x > 0) + encodedByte = encodedByte & 128; + out.write(encodedByte); + } while ( x > 0 ); + } +} diff --git a/src/zutil/parser/binary/BinaryFieldData.java b/src/zutil/parser/binary/BinaryFieldData.java index dab9ea9..2a7949d 100755 --- a/src/zutil/parser/binary/BinaryFieldData.java +++ b/src/zutil/parser/binary/BinaryFieldData.java @@ -101,7 +101,7 @@ public class BinaryFieldData { else if (field.getType() == String.class) field.set(obj, new String(ByteUtil.getReverseByteOrder(data), StandardCharsets.ISO_8859_1)); else - throw new UnsupportedOperationException("Unsupported BinaryStruct field class: "+ field.getClass()); + throw new UnsupportedOperationException("Unsupported BinaryStruct field class: "+ field.getType()); } catch (IllegalAccessException e){ e.printStackTrace(); } diff --git a/src/zutil/parser/binary/BinaryStruct.java b/src/zutil/parser/binary/BinaryStruct.java index 5f98c01..2a0b0ac 100755 --- a/src/zutil/parser/binary/BinaryStruct.java +++ b/src/zutil/parser/binary/BinaryStruct.java @@ -30,6 +30,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * A interface that indicate that the implementing class can + * be serialized into a linear binary stream. + * * Created by Ziver on 2016-01-28. */ public interface BinaryStruct { @@ -47,7 +50,9 @@ public interface BinaryStruct { } /** - * Can be used for fields that are of variable length. + * Can be used for fields that are of variable length. This interface + * is only applicable for reading from a stream. + * TODO: Length must be manually set when writing. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @@ -56,8 +61,8 @@ public interface BinaryStruct { int index(); /** The name of the field that will contain the length of the data to read. */ String lengthField(); - /** Defines the multiplier used on the lengthField to convert to length in bits which is used internally. - * Default value is 8. */ + /** Defines the multiplier used on the lengthField parameter to convert the length in bits to + * a user defined value. Default value is 8 (which converts length to nr of bytes). */ int multiplier() default 8; } diff --git a/test/zutil/net/mqtt/packet/MqttPacketConnectTest.java b/test/zutil/net/mqtt/packet/MqttPacketConnectTest.java new file mode 100755 index 0000000..752f245 --- /dev/null +++ b/test/zutil/net/mqtt/packet/MqttPacketConnectTest.java @@ -0,0 +1,65 @@ +package zutil.net.mqtt.packet; + +import org.junit.Test; +import zutil.converter.Converter; +import zutil.net.mqtt.packet.MqttPacketConnect; +import zutil.parser.binary.BinaryStructInputStream; +import zutil.parser.binary.BinaryStructOutputStream; + +import java.io.IOException; + +import static org.junit.Assert.*; + + +public class MqttPacketConnectTest { + + char[] data = new char[]{ + 0b0000_0000, // length + 0b0000_0100, // length + 0b0100_1101, // 'M' + 0b0101_0001, // 'Q' + 0b0101_0100, // 'T' + 0b0101_0100, // 'T' + + 0b0000_0100, // Prot. Level + + 0b1100_1110, // Flags + + 0b0000_0000, // Keep alive + 0b0000_1010, // Keep alive + }; + + + @Test + public void decode(){ + MqttPacketConnect obj = new MqttPacketConnect(); + BinaryStructInputStream.read(obj, Converter.toBytes(data)); + + assertEquals("MQTT", obj.protocolName); + assertEquals(4, obj.protocolLevel); + assertEquals(10, obj.keepAlive); + + assertTrue(obj.flagUsername); + assertTrue(obj.flagPassword); + assertFalse(obj.flagWillRetain); + assertEquals(1, obj.flagWillQoS); + assertTrue(obj.flagWillFlag); + assertTrue(obj.flagCleanSession); + } + + @Test + public void encode() throws IOException { + MqttPacketConnect obj = new MqttPacketConnect(); + obj.keepAlive = 10; + + obj.flagUsername = true; + obj.flagPassword = true; + obj.flagWillRetain = false; + obj.flagWillQoS = 1; + obj.flagWillFlag = true; + obj.flagCleanSession = true; + + assertArrayEquals(Converter.toBytes(data), + BinaryStructOutputStream.serialize(obj)); + } +} \ No newline at end of file