-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit bb68e94
Showing
34 changed files
with
5,050 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.") | ||
} |
Oops, something went wrong.