Files
mochi-mqtt/packets/fixedheader.go
2019-09-22 15:11:02 +01:00

95 lines
2.2 KiB
Go

package packets
import (
"bytes"
"errors"
)
// FixedHeader contains the values of the fixed header portion of the MQTT packet.
type FixedHeader struct {
// Type is the type of the packet (PUBLISH, SUBSCRIBE, etc) from bits 7 - 4 (byte 1).
Type byte
// Dup indicates if the packet is a duplicate.
Dup bool
// Qos byte indicates the quality of service expected.
Qos byte
// Retain indicates whether the message should be retained.
Retain bool
// Remaining is the number of remaining bytes in the payload.
Remaining int
}
// Encode encodes the FixedHeader and returns a bytes buffer.
func (fh *FixedHeader) encode() bytes.Buffer {
var encoded bytes.Buffer
// Encode flags.
encoded.WriteByte(fh.Type<<4 | encodeBool(fh.Dup)<<3 | fh.Qos<<1 | encodeBool(fh.Retain))
// Determine encoded length and write the buffer.
encoded.Write(encodeLength(fh.Remaining))
return encoded
}
// decode extracts the specification bits from the header byte.
func (fh *FixedHeader) decode(headerByte byte) error {
// Get the message type from the first 4 bytes.
fh.Type = headerByte >> 4
// @SPEC [MQTT-2.2.2-1]
// Where a flag bit is marked as “Reserved” in Table 2.2 - Flag Bits,
// it is reserved for future use and MUST be set to the value listed in that table.
switch fh.Type {
case Publish:
fh.Dup = (headerByte>>3)&0x01 > 0 // Extract flags. Check if message is duplicate.
fh.Qos = (headerByte >> 1) & 0x03 // Extract QoS flag.
fh.Retain = headerByte&0x01 > 0 // Extract retain flag.
case Pubrel:
fh.Qos = (headerByte >> 1) & 0x03
case Subscribe:
fh.Qos = (headerByte >> 1) & 0x03
case Unsubscribe:
fh.Qos = (headerByte >> 1) & 0x03
default:
// [MQTT-2.2.2-2]
// If invalid flags are received, the receiver MUST close the Network Connection.
if (headerByte>>3)&0x01 > 0 || (headerByte>>1)&0x03 > 0 || headerByte&0x01 > 0 {
return errors.New(ErrInvalidFlags)
}
}
return nil
}
// encodeLength creates length bits for the header.
func encodeLength(length int) []byte {
encodedLength := make([]byte, 0, 8)
for {
digit := byte(length % 128)
length /= 128
if length > 0 {
digit |= 0x80
}
encodedLength = append(encodedLength, digit)
if length == 0 {
break
}
}
return encodedLength
}