You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.0 KiB

  1. package packet
  2. // CONNECT represents a CONNECT Packet.
  3. type CONNECT struct {
  4. base
  5. // clientID is the Client Identifier of the payload.
  6. clientID []byte
  7. // userName is the User Name of the payload.
  8. userName []byte
  9. // password is the Password of the payload.
  10. password []byte
  11. // cleanSession is the Clean Session of the variable header.
  12. cleanSession bool
  13. // keepAlive is the Keep Alive of the variable header.
  14. keepAlive uint16
  15. // willTopic is the Will Topic of the payload.
  16. willTopic []byte
  17. // willMessage is the Will Message of the payload.
  18. willMessage []byte
  19. // willQoS is the Will QoS of the variable header.
  20. willQoS byte
  21. // willRetain is the Will Retain of the variable header.
  22. willRetain bool
  23. }
  24. // setFixedHeader sets the fixed header to the Packet.
  25. func (p *CONNECT) setFixedHeader() {
  26. // Append the first byte to the fixed header.
  27. p.fixedHeader = append(p.fixedHeader, TypeCONNECT<<4)
  28. // Append the Remaining Length to the fixed header.
  29. p.appendRemainingLength()
  30. }
  31. // setVariableHeader sets the variable header to the Packet.
  32. func (p *CONNECT) setVariableHeader() {
  33. // Convert the Keep Alive to the slice.
  34. keepAlive := encodeUint16(p.keepAlive)
  35. // Create a variable header and set it to the Packet.
  36. p.variableHeader = []byte{
  37. 0x00, // Length MSB (0)
  38. 0x04, // Length LSB (4)
  39. 0x4D, // 'M'
  40. 0x51, // 'Q'
  41. 0x54, // 'T'
  42. 0x54, // 'T'
  43. 0x04, // Level(4)
  44. p.connectFlags(), // Connect Flags
  45. keepAlive[0], // Keep Alive MSB
  46. keepAlive[1], // Keep Alive LSB
  47. }
  48. }
  49. // setPayload sets the payload to the Packet.
  50. func (p *CONNECT) setPayload() {
  51. // Append the Client Identifier to the payload.
  52. p.payload = appendLenStr(p.payload, p.clientID)
  53. // Append the Will Topic and the Will Message to the payload
  54. // if the Packet has them.
  55. if p.will() {
  56. p.payload = appendLenStr(p.payload, p.willTopic)
  57. p.payload = appendLenStr(p.payload, p.willMessage)
  58. }
  59. // Append the User Name to the payload if the Packet has it.
  60. if len(p.userName) > 0 {
  61. p.payload = appendLenStr(p.payload, p.userName)
  62. }
  63. // Append the Password to the payload if the Packet has it.
  64. if len(p.password) > 0 {
  65. p.payload = appendLenStr(p.payload, p.password)
  66. }
  67. }
  68. // connectFlags creates and returns a byte which represents the Connect Flags.
  69. func (p *CONNECT) connectFlags() byte {
  70. // Create a byte which represents the Connect Flags.
  71. var b byte
  72. // Set 1 to the Bit 7 if the Packet has the User Name.
  73. if len(p.userName) > 0 {
  74. b |= 0x80
  75. }
  76. // Set 1 to the Bit 6 if the Packet has the Password.
  77. if len(p.password) > 0 {
  78. b |= 0x40
  79. }
  80. // Set 1 to the Bit 5 if the Will Retain is true.
  81. if p.willRetain {
  82. b |= 0x20
  83. }
  84. // Set the value of the Will QoS to the Bit 4 and 3.
  85. b |= p.willQoS << 3
  86. // Set 1 to the Bit 2 if the Packet has the Will Topic and the Will Message.
  87. if p.will() {
  88. b |= 0x04
  89. }
  90. // Set 1 to the Bit 1 if the Clean Session is true.
  91. if p.cleanSession {
  92. b |= 0x02
  93. }
  94. // Return the byte.
  95. return b
  96. }
  97. // will return true if both the Will Topic and the Will Message are not zero-byte.
  98. func (p *CONNECT) will() bool {
  99. return len(p.willTopic) > 0 && len(p.willMessage) > 0
  100. }
  101. // NewCONNECT creates and returns a CONNECT Packet.
  102. func NewCONNECT(opts *CONNECTOptions) (Packet, error) {
  103. // Initialize the options.
  104. if opts == nil {
  105. opts = &CONNECTOptions{}
  106. }
  107. // Validate the options.
  108. if err := opts.validate(); err != nil {
  109. return nil, err
  110. }
  111. // Create a CONNECT Packet.
  112. p := &CONNECT{
  113. clientID: opts.ClientID,
  114. userName: opts.UserName,
  115. password: opts.Password,
  116. cleanSession: opts.CleanSession,
  117. keepAlive: opts.KeepAlive,
  118. willTopic: opts.WillTopic,
  119. willMessage: opts.WillMessage,
  120. willQoS: opts.WillQoS,
  121. willRetain: opts.WillRetain,
  122. }
  123. // Set the variable header to the Packet.
  124. p.setVariableHeader()
  125. // Set the payload to the Packet.
  126. p.setPayload()
  127. // Set the fixed header to the packet.
  128. p.setFixedHeader()
  129. // Return the Packet.
  130. return p, nil
  131. }