Rework some things into packages (#489)
This commit is contained in:
184
header/header.go
Normal file
184
header/header.go
Normal file
@ -0,0 +1,184 @@
|
||||
package header
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//Version 1 header:
|
||||
// 0 31
|
||||
// |-----------------------------------------------------------------------|
|
||||
// | Version (uint4) | Type (uint4) | Subtype (uint8) | Reserved (uint16) | 32
|
||||
// |-----------------------------------------------------------------------|
|
||||
// | Remote index (uint32) | 64
|
||||
// |-----------------------------------------------------------------------|
|
||||
// | Message counter | 96
|
||||
// | (uint64) | 128
|
||||
// |-----------------------------------------------------------------------|
|
||||
// | payload... |
|
||||
|
||||
type m map[string]interface{}
|
||||
|
||||
const (
|
||||
Version uint8 = 1
|
||||
Len = 16
|
||||
)
|
||||
|
||||
type MessageType uint8
|
||||
type MessageSubType uint8
|
||||
|
||||
const (
|
||||
Handshake MessageType = 0
|
||||
Message MessageType = 1
|
||||
RecvError MessageType = 2
|
||||
LightHouse MessageType = 3
|
||||
Test MessageType = 4
|
||||
CloseTunnel MessageType = 5
|
||||
)
|
||||
|
||||
var typeMap = map[MessageType]string{
|
||||
Handshake: "handshake",
|
||||
Message: "message",
|
||||
RecvError: "recvError",
|
||||
LightHouse: "lightHouse",
|
||||
Test: "test",
|
||||
CloseTunnel: "closeTunnel",
|
||||
}
|
||||
|
||||
const (
|
||||
TestRequest MessageSubType = 0
|
||||
TestReply MessageSubType = 1
|
||||
)
|
||||
|
||||
const (
|
||||
HandshakeIXPSK0 MessageSubType = 0
|
||||
HandshakeXXPSK0 MessageSubType = 1
|
||||
)
|
||||
|
||||
var ErrHeaderTooShort = errors.New("header is too short")
|
||||
|
||||
var subTypeTestMap = map[MessageSubType]string{
|
||||
TestRequest: "testRequest",
|
||||
TestReply: "testReply",
|
||||
}
|
||||
|
||||
var subTypeNoneMap = map[MessageSubType]string{0: "none"}
|
||||
|
||||
var subTypeMap = map[MessageType]*map[MessageSubType]string{
|
||||
Message: &subTypeNoneMap,
|
||||
RecvError: &subTypeNoneMap,
|
||||
LightHouse: &subTypeNoneMap,
|
||||
Test: &subTypeTestMap,
|
||||
CloseTunnel: &subTypeNoneMap,
|
||||
Handshake: {
|
||||
HandshakeIXPSK0: "ix_psk0",
|
||||
},
|
||||
}
|
||||
|
||||
type H struct {
|
||||
Version uint8
|
||||
Type MessageType
|
||||
Subtype MessageSubType
|
||||
Reserved uint16
|
||||
RemoteIndex uint32
|
||||
MessageCounter uint64
|
||||
}
|
||||
|
||||
// Encode uses the provided byte array to encode the provided header values into.
|
||||
// Byte array must be capped higher than HeaderLen or this will panic
|
||||
func Encode(b []byte, v uint8, t MessageType, st MessageSubType, ri uint32, c uint64) []byte {
|
||||
b = b[:Len]
|
||||
b[0] = v<<4 | byte(t&0x0f)
|
||||
b[1] = byte(st)
|
||||
binary.BigEndian.PutUint16(b[2:4], 0)
|
||||
binary.BigEndian.PutUint32(b[4:8], ri)
|
||||
binary.BigEndian.PutUint64(b[8:16], c)
|
||||
return b
|
||||
}
|
||||
|
||||
// String creates a readable string representation of a header
|
||||
func (h *H) String() string {
|
||||
if h == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("ver=%d type=%s subtype=%s reserved=%#x remoteindex=%v messagecounter=%v",
|
||||
h.Version, h.TypeName(), h.SubTypeName(), h.Reserved, h.RemoteIndex, h.MessageCounter)
|
||||
}
|
||||
|
||||
// MarshalJSON creates a json string representation of a header
|
||||
func (h *H) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(m{
|
||||
"version": h.Version,
|
||||
"type": h.TypeName(),
|
||||
"subType": h.SubTypeName(),
|
||||
"reserved": h.Reserved,
|
||||
"remoteIndex": h.RemoteIndex,
|
||||
"messageCounter": h.MessageCounter,
|
||||
})
|
||||
}
|
||||
|
||||
// Encode turns header into bytes
|
||||
func (h *H) Encode(b []byte) ([]byte, error) {
|
||||
if h == nil {
|
||||
return nil, errors.New("nil header")
|
||||
}
|
||||
|
||||
return Encode(b, h.Version, h.Type, h.Subtype, h.RemoteIndex, h.MessageCounter), nil
|
||||
}
|
||||
|
||||
// Parse is a helper function to parses given bytes into new Header struct
|
||||
func (h *H) Parse(b []byte) error {
|
||||
if len(b) < Len {
|
||||
return ErrHeaderTooShort
|
||||
}
|
||||
// get upper 4 bytes
|
||||
h.Version = uint8((b[0] >> 4) & 0x0f)
|
||||
// get lower 4 bytes
|
||||
h.Type = MessageType(b[0] & 0x0f)
|
||||
h.Subtype = MessageSubType(b[1])
|
||||
h.Reserved = binary.BigEndian.Uint16(b[2:4])
|
||||
h.RemoteIndex = binary.BigEndian.Uint32(b[4:8])
|
||||
h.MessageCounter = binary.BigEndian.Uint64(b[8:16])
|
||||
return nil
|
||||
}
|
||||
|
||||
// TypeName will transform the headers message type into a human string
|
||||
func (h *H) TypeName() string {
|
||||
return TypeName(h.Type)
|
||||
}
|
||||
|
||||
// TypeName will transform a nebula message type into a human string
|
||||
func TypeName(t MessageType) string {
|
||||
if n, ok := typeMap[t]; ok {
|
||||
return n
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// SubTypeName will transform the headers message sub type into a human string
|
||||
func (h *H) SubTypeName() string {
|
||||
return SubTypeName(h.Type, h.Subtype)
|
||||
}
|
||||
|
||||
// SubTypeName will transform a nebula message sub type into a human string
|
||||
func SubTypeName(t MessageType, s MessageSubType) string {
|
||||
if n, ok := subTypeMap[t]; ok {
|
||||
if x, ok := (*n)[s]; ok {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// NewHeader turns bytes into a header
|
||||
func NewHeader(b []byte) (*H, error) {
|
||||
h := new(H)
|
||||
if err := h.Parse(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
115
header/header_test.go
Normal file
115
header/header_test.go
Normal file
@ -0,0 +1,115 @@
|
||||
package header
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type headerTest struct {
|
||||
expectedBytes []byte
|
||||
*H
|
||||
}
|
||||
|
||||
// 0001 0010 00010010
|
||||
var headerBigEndianTests = []headerTest{{
|
||||
expectedBytes: []byte{0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9},
|
||||
// 1010 0000
|
||||
H: &H{
|
||||
// 1111 1+2+4+8 = 15
|
||||
Version: 5,
|
||||
Type: 4,
|
||||
Subtype: 0,
|
||||
Reserved: 0,
|
||||
RemoteIndex: 10,
|
||||
MessageCounter: 9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
for _, tt := range headerBigEndianTests {
|
||||
b, err := tt.Encode(make([]byte, Len))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expectedBytes, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
for _, tt := range headerBigEndianTests {
|
||||
b := tt.expectedBytes
|
||||
parsedHeader := &H{}
|
||||
parsedHeader.Parse(b)
|
||||
|
||||
if !reflect.DeepEqual(tt.H, parsedHeader) {
|
||||
t.Fatalf("got %#v; want %#v", parsedHeader, tt.H)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeName(t *testing.T) {
|
||||
assert.Equal(t, "test", TypeName(Test))
|
||||
assert.Equal(t, "test", (&H{Type: Test}).TypeName())
|
||||
|
||||
assert.Equal(t, "unknown", TypeName(99))
|
||||
assert.Equal(t, "unknown", (&H{Type: 99}).TypeName())
|
||||
}
|
||||
|
||||
func TestSubTypeName(t *testing.T) {
|
||||
assert.Equal(t, "testRequest", SubTypeName(Test, TestRequest))
|
||||
assert.Equal(t, "testRequest", (&H{Type: Test, Subtype: TestRequest}).SubTypeName())
|
||||
|
||||
assert.Equal(t, "unknown", SubTypeName(99, TestRequest))
|
||||
assert.Equal(t, "unknown", (&H{Type: 99, Subtype: TestRequest}).SubTypeName())
|
||||
|
||||
assert.Equal(t, "unknown", SubTypeName(Test, 99))
|
||||
assert.Equal(t, "unknown", (&H{Type: Test, Subtype: 99}).SubTypeName())
|
||||
|
||||
assert.Equal(t, "none", SubTypeName(Message, 0))
|
||||
assert.Equal(t, "none", (&H{Type: Message, Subtype: 0}).SubTypeName())
|
||||
}
|
||||
|
||||
func TestTypeMap(t *testing.T) {
|
||||
// Force people to document this stuff
|
||||
assert.Equal(t, map[MessageType]string{
|
||||
Handshake: "handshake",
|
||||
Message: "message",
|
||||
RecvError: "recvError",
|
||||
LightHouse: "lightHouse",
|
||||
Test: "test",
|
||||
CloseTunnel: "closeTunnel",
|
||||
}, typeMap)
|
||||
|
||||
assert.Equal(t, map[MessageType]*map[MessageSubType]string{
|
||||
Message: &subTypeNoneMap,
|
||||
RecvError: &subTypeNoneMap,
|
||||
LightHouse: &subTypeNoneMap,
|
||||
Test: &subTypeTestMap,
|
||||
CloseTunnel: &subTypeNoneMap,
|
||||
Handshake: {
|
||||
HandshakeIXPSK0: "ix_psk0",
|
||||
},
|
||||
}, subTypeMap)
|
||||
}
|
||||
|
||||
func TestHeader_String(t *testing.T) {
|
||||
assert.Equal(
|
||||
t,
|
||||
"ver=100 type=test subtype=testRequest reserved=0x63 remoteindex=98 messagecounter=97",
|
||||
(&H{100, Test, TestRequest, 99, 98, 97}).String(),
|
||||
)
|
||||
}
|
||||
|
||||
func TestHeader_MarshalJSON(t *testing.T) {
|
||||
b, err := (&H{100, Test, TestRequest, 99, 98, 97}).MarshalJSON()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(
|
||||
t,
|
||||
"{\"messageCounter\":97,\"remoteIndex\":98,\"reserved\":99,\"subType\":\"testRequest\",\"type\":\"test\",\"version\":100}",
|
||||
string(b),
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user