connect.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright (c) 2021 IBM Corp and others.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v2.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * https://www.eclipse.org/legal/epl-2.0/
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Allan Stockdill-Mander
  15. */
  16. package packets
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io"
  21. )
  22. // ConnectPacket is an internal representation of the fields of the
  23. // Connect MQTT packet
  24. type ConnectPacket struct {
  25. FixedHeader
  26. ProtocolName string
  27. ProtocolVersion byte
  28. CleanSession bool
  29. WillFlag bool
  30. WillQos byte
  31. WillRetain bool
  32. UsernameFlag bool
  33. PasswordFlag bool
  34. ReservedBit byte
  35. Keepalive uint16
  36. ClientIdentifier string
  37. WillTopic string
  38. WillMessage []byte
  39. Username string
  40. Password []byte
  41. }
  42. func (c *ConnectPacket) String() string {
  43. var password string
  44. if len(c.Password) > 0 {
  45. password = "<redacted>"
  46. }
  47. return fmt.Sprintf("%s protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalive: %d clientId: %s willtopic: %s willmessage: %s Username: %s Password: %s", c.FixedHeader, 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, password)
  48. }
  49. func (c *ConnectPacket) Write(w io.Writer) error {
  50. var body bytes.Buffer
  51. var err error
  52. body.Write(encodeString(c.ProtocolName))
  53. body.WriteByte(c.ProtocolVersion)
  54. 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)
  55. body.Write(encodeUint16(c.Keepalive))
  56. body.Write(encodeString(c.ClientIdentifier))
  57. if c.WillFlag {
  58. body.Write(encodeString(c.WillTopic))
  59. body.Write(encodeBytes(c.WillMessage))
  60. }
  61. if c.UsernameFlag {
  62. body.Write(encodeString(c.Username))
  63. }
  64. if c.PasswordFlag {
  65. body.Write(encodeBytes(c.Password))
  66. }
  67. c.FixedHeader.RemainingLength = body.Len()
  68. packet := c.FixedHeader.pack()
  69. packet.Write(body.Bytes())
  70. _, err = packet.WriteTo(w)
  71. return err
  72. }
  73. // Unpack decodes the details of a ControlPacket after the fixed
  74. // header has been read
  75. func (c *ConnectPacket) Unpack(b io.Reader) error {
  76. var err error
  77. c.ProtocolName, err = decodeString(b)
  78. if err != nil {
  79. return err
  80. }
  81. c.ProtocolVersion, err = decodeByte(b)
  82. if err != nil {
  83. return err
  84. }
  85. options, err := decodeByte(b)
  86. if err != nil {
  87. return err
  88. }
  89. c.ReservedBit = 1 & options
  90. c.CleanSession = 1&(options>>1) > 0
  91. c.WillFlag = 1&(options>>2) > 0
  92. c.WillQos = 3 & (options >> 3)
  93. c.WillRetain = 1&(options>>5) > 0
  94. c.PasswordFlag = 1&(options>>6) > 0
  95. c.UsernameFlag = 1&(options>>7) > 0
  96. c.Keepalive, err = decodeUint16(b)
  97. if err != nil {
  98. return err
  99. }
  100. c.ClientIdentifier, err = decodeString(b)
  101. if err != nil {
  102. return err
  103. }
  104. if c.WillFlag {
  105. c.WillTopic, err = decodeString(b)
  106. if err != nil {
  107. return err
  108. }
  109. c.WillMessage, err = decodeBytes(b)
  110. if err != nil {
  111. return err
  112. }
  113. }
  114. if c.UsernameFlag {
  115. c.Username, err = decodeString(b)
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. if c.PasswordFlag {
  121. c.Password, err = decodeBytes(b)
  122. if err != nil {
  123. return err
  124. }
  125. }
  126. return nil
  127. }
  128. // Validate performs validation of the fields of a Connect packet
  129. func (c *ConnectPacket) Validate() byte {
  130. if c.PasswordFlag && !c.UsernameFlag {
  131. return ErrRefusedBadUsernameOrPassword
  132. }
  133. if c.ReservedBit != 0 {
  134. // Bad reserved bit
  135. return ErrProtocolViolation
  136. }
  137. if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) {
  138. // Mismatched or unsupported protocol version
  139. return ErrRefusedBadProtocolVersion
  140. }
  141. if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" {
  142. // Bad protocol name
  143. return ErrProtocolViolation
  144. }
  145. if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 {
  146. // Bad size field
  147. return ErrProtocolViolation
  148. }
  149. if len(c.ClientIdentifier) == 0 && !c.CleanSession {
  150. // Bad client identifier
  151. return ErrRefusedIDRejected
  152. }
  153. return Accepted
  154. }
  155. // Details returns a Details struct containing the Qos and
  156. // MessageID of this ControlPacket
  157. func (c *ConnectPacket) Details() Details {
  158. return Details{Qos: 0, MessageID: 0}
  159. }