Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zhenjl committed Dec 1, 2014
0 parents commit bb68e94
Show file tree
Hide file tree
Showing 34 changed files with 5,050 additions and 0 deletions.
152 changes: 152 additions & 0 deletions connack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) 2014 Dataence, LLC. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package message

import "fmt"

// The CONNACK Packet is the packet sent by the Server in response to a CONNECT Packet
// received from a Client. The first packet sent from the Server to the Client MUST
// be a CONNACK Packet [MQTT-3.2.0-1].
//
// If the Client does not receive a CONNACK Packet from the Server within a reasonable
// amount of time, the Client SHOULD close the Network Connection. A "reasonable" amount
// of time depends on the type of application and the communications infrastructure.
type ConnackMessage struct {
header

sessionPresent bool
returnCode ConnackCode
}

var _ Message = (*ConnackMessage)(nil)

// NewConnackMessage creates a new CONNACK message
func NewConnackMessage() *ConnackMessage {
msg := &ConnackMessage{}
msg.SetType(CONNACK)

return msg
}

// String returns a string representation of the CONNACK message
func (this ConnackMessage) String() string {
return fmt.Sprintf("%v\nSession Present: %t\nReturn code: %v\n",
this.header, this.sessionPresent, this.returnCode)
}

// SessionPresent returns the session present flag value
func (this *ConnackMessage) SessionPresent() bool {
return this.sessionPresent
}

// SetSessionPresent sets the value of the session present flag
func (this *ConnackMessage) SetSessionPresent(v bool) {
if v {
this.sessionPresent = true
} else {
this.sessionPresent = false
}
}

// ReturnCode returns the return code received for the CONNECT message. The return
// type is an error
func (this *ConnackMessage) ReturnCode() ConnackCode {
return this.returnCode
}

func (this *ConnackMessage) SetReturnCode(ret ConnackCode) {
this.returnCode = ret
}

func (this *ConnackMessage) Len() int {
ml := this.msglen()

if err := this.SetRemainingLength(int32(ml)); err != nil {
return 0
}

return this.header.msglen() + ml
}

func (this *ConnackMessage) Decode(src []byte) (int, error) {
total := 0

n, err := this.header.decode(src)
total += n
if err != nil {
return total, err
}

b := src[total]

if b&254 != 0 {
return 0, fmt.Errorf("connack/Decode: Bits 7-1 in Connack Acknowledge Flags byte (1) are not 0")
}

this.sessionPresent = b&0x1 == 1
total++

b = src[total]

// Read return code
if b > 5 {
return 0, fmt.Errorf("connack/Decode: Invalid CONNACK return code (%d)", b)
}

this.returnCode = ConnackCode(b)
total++

return total, nil
}

func (this *ConnackMessage) Encode(dst []byte) (int, error) {
// CONNACK remaining length fixed at 2 bytes
hl := this.header.msglen()
ml := this.msglen()

if len(dst) < hl+ml {
return 0, fmt.Errorf("connack/Encode: Insufficient buffer size. Expecting %d, got %d.", hl+ml, len(dst))
}

if err := this.SetRemainingLength(int32(ml)); err != nil {
return 0, err
}

total := 0

n, err := this.header.encode(dst[total:])
total += n
if err != nil {
return 0, err
}

if this.sessionPresent {
dst[total] = 1
}
total++

if this.returnCode > 5 {
return total, fmt.Errorf("connack/Encode: Invalid CONNACK return code (%d)", this.returnCode)
}

dst[total] = this.returnCode.Value()
total++

return total, nil
}

func (this *ConnackMessage) msglen() int {
return 2
}
160 changes: 160 additions & 0 deletions connack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright (c) 2014 Dataence, LLC. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package message

import (
"testing"

"github.com/dataence/assert"
)

func TestConnackMessageFields(t *testing.T) {
msg := NewConnackMessage()

msg.SetSessionPresent(true)
assert.True(t, true, msg.SessionPresent(), "Error setting session present flag.")

msg.SetSessionPresent(false)
assert.False(t, true, msg.SessionPresent(), "Error setting session present flag.")

msg.SetReturnCode(ConnectionAccepted)
assert.Equal(t, true, ConnectionAccepted, msg.ReturnCode(), "Error setting return code.")
}

func TestConnackMessageDecode(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
0, // session not present
0, // connection accepted
}

msg := NewConnackMessage()

n, err := msg.Decode(msgBytes)

assert.NoError(t, true, err, "Error decoding message.")
assert.Equal(t, true, len(msgBytes), n, "Error decoding message.")
assert.False(t, true, msg.SessionPresent(), "Error decoding session present flag.")
assert.Equal(t, true, ConnectionAccepted, msg.ReturnCode(), "Error decoding return code.")
}

// testing wrong message length
func TestConnackMessageDecode2(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
3,
0, // session not present
0, // connection accepted
}

msg := NewConnackMessage()

_, err := msg.Decode(msgBytes)
assert.Error(t, true, err, "Error decoding message.")
}

// testing wrong message size
func TestConnackMessageDecode3(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
0, // session not present
}

msg := NewConnackMessage()

_, err := msg.Decode(msgBytes)
assert.Error(t, true, err, "Error decoding message.")
}

// testing wrong reserve bits
func TestConnackMessageDecode4(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
64, // <- wrong size
0, // connection accepted
}

msg := NewConnackMessage()

_, err := msg.Decode(msgBytes)
assert.Error(t, true, err, "Error decoding message.")
}

// testing invalid return code
func TestConnackMessageDecode5(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
0,
6, // <- wrong code
}

msg := NewConnackMessage()

_, err := msg.Decode(msgBytes)
assert.Error(t, true, err, "Error decoding message.")
}

func TestConnackMessageEncode(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
1, // session present
0, // connection accepted
}

msg := NewConnackMessage()
msg.SetReturnCode(ConnectionAccepted)
msg.SetSessionPresent(true)

dst := make([]byte, 10)
n, err := msg.Encode(dst)

assert.NoError(t, true, err, "Error decoding message.")
assert.Equal(t, true, len(msgBytes), n, "Error encoding message.")
assert.Equal(t, true, msgBytes, dst[:n], "Error encoding connack message.")
}

// test to ensure encoding and decoding are the same
// decode, encode, and decode again
func TestConnackDecodeEncodeEquiv(t *testing.T) {
msgBytes := []byte{
byte(CONNACK << 4),
2,
0, // session not present
0, // connection accepted
}

msg := NewConnackMessage()
n, err := msg.Decode(msgBytes)

assert.NoError(t, true, err, "Error decoding message.")
assert.Equal(t, true, len(msgBytes), n, "Error decoding message.")

dst := make([]byte, 100)
n2, err := msg.Encode(dst)

assert.NoError(t, true, err, "Error decoding message.")
assert.Equal(t, true, len(msgBytes), n2, "Error decoding message.")
assert.Equal(t, true, msgBytes, dst[:n2], "Error decoding message.")

n3, err := msg.Decode(dst)

assert.NoError(t, true, err, "Error decoding message.")
assert.Equal(t, true, len(msgBytes), n3, "Error decoding message.")
}
Loading

0 comments on commit bb68e94

Please sign in to comment.