1package packets 2 3import ( 4 "bytes" 5 "fmt" 6 "io" 7) 8 9//ConnectPacket is an internal representation of the fields of the 10//Connect MQTT packet 11type ConnectPacket struct { 12 FixedHeader 13 ProtocolName string 14 ProtocolVersion byte 15 CleanSession bool 16 WillFlag bool 17 WillQos byte 18 WillRetain bool 19 UsernameFlag bool 20 PasswordFlag bool 21 ReservedBit byte 22 Keepalive uint16 23 24 ClientIdentifier string 25 WillTopic string 26 WillMessage []byte 27 Username string 28 Password []byte 29} 30 31func (c *ConnectPacket) String() string { 32 str := fmt.Sprintf("%s\n", c.FixedHeader) 33 str += fmt.Sprintf("protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalive: %d\nclientId: %s\nwilltopic: %s\nwillmessage: %s\nUsername: %s\nPassword: %s\n", c.ProtocolVersion, c.ProtocolName, c.CleanSession, c.WillFlag, c.WillQos, c.WillRetain, c.UsernameFlag, c.PasswordFlag, c.Keepalive, c.ClientIdentifier, c.WillTopic, c.WillMessage, c.Username, c.Password) 34 return str 35} 36 37func (c *ConnectPacket) Write(w io.Writer) error { 38 var body bytes.Buffer 39 var err error 40 41 body.Write(encodeString(c.ProtocolName)) 42 body.WriteByte(c.ProtocolVersion) 43 body.WriteByte(boolToByte(c.CleanSession)<<1 | boolToByte(c.WillFlag)<<2 | c.WillQos<<3 | boolToByte(c.WillRetain)<<5 | boolToByte(c.PasswordFlag)<<6 | boolToByte(c.UsernameFlag)<<7) 44 body.Write(encodeUint16(c.Keepalive)) 45 body.Write(encodeString(c.ClientIdentifier)) 46 if c.WillFlag { 47 body.Write(encodeString(c.WillTopic)) 48 body.Write(encodeBytes(c.WillMessage)) 49 } 50 if c.UsernameFlag { 51 body.Write(encodeString(c.Username)) 52 } 53 if c.PasswordFlag { 54 body.Write(encodeBytes(c.Password)) 55 } 56 c.FixedHeader.RemainingLength = body.Len() 57 packet := c.FixedHeader.pack() 58 packet.Write(body.Bytes()) 59 _, err = packet.WriteTo(w) 60 61 return err 62} 63 64//Unpack decodes the details of a ControlPacket after the fixed 65//header has been read 66func (c *ConnectPacket) Unpack(b io.Reader) error { 67 c.ProtocolName = decodeString(b) 68 c.ProtocolVersion = decodeByte(b) 69 options := decodeByte(b) 70 c.ReservedBit = 1 & options 71 c.CleanSession = 1&(options>>1) > 0 72 c.WillFlag = 1&(options>>2) > 0 73 c.WillQos = 3 & (options >> 3) 74 c.WillRetain = 1&(options>>5) > 0 75 c.PasswordFlag = 1&(options>>6) > 0 76 c.UsernameFlag = 1&(options>>7) > 0 77 c.Keepalive = decodeUint16(b) 78 c.ClientIdentifier = decodeString(b) 79 if c.WillFlag { 80 c.WillTopic = decodeString(b) 81 c.WillMessage = decodeBytes(b) 82 } 83 if c.UsernameFlag { 84 c.Username = decodeString(b) 85 } 86 if c.PasswordFlag { 87 c.Password = decodeBytes(b) 88 } 89 90 return nil 91} 92 93//Validate performs validation of the fields of a Connect packet 94func (c *ConnectPacket) Validate() byte { 95 if c.PasswordFlag && !c.UsernameFlag { 96 return ErrRefusedBadUsernameOrPassword 97 } 98 if c.ReservedBit != 0 { 99 //Bad reserved bit 100 return ErrProtocolViolation 101 } 102 if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) { 103 //Mismatched or unsupported protocol version 104 return ErrRefusedBadProtocolVersion 105 } 106 if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" { 107 //Bad protocol name 108 return ErrProtocolViolation 109 } 110 if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 { 111 //Bad size field 112 return ErrProtocolViolation 113 } 114 return Accepted 115} 116 117//Details returns a Details struct containing the Qos and 118//MessageID of this ControlPacket 119func (c *ConnectPacket) Details() Details { 120 return Details{Qos: 0, MessageID: 0} 121} 122