Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Commit

Permalink
TCPCL: Contact Header
Browse files Browse the repository at this point in the history
  • Loading branch information
oxzi committed Sep 2, 2019
1 parent c556a66 commit 3889f27
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
79 changes: 79 additions & 0 deletions cla/tcpcl/contact_header.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package tcpcl

import (
"bytes"
"fmt"
)

// ContactFlags are single-bit flags used in the ContactHeader.
type ContactFlags uint8

const (
// ContactFlags_NONE is a default for no flags
ContactFlags_NONE ContactFlags = 0x00

// ContactFlags_CAN_TLS indicates that the sending peer is capable of TLS security.
ContactFlags_CAN_TLS ContactFlags = 0x01

// contactFlags_INVALID is a bit field of all invalid ContactFlags.
contactFlags_INVALID ContactFlags = 0xFE
)

func (cf ContactFlags) String() string {
switch cf {
case ContactFlags_NONE:
return "NONE"
case ContactFlags_CAN_TLS:
return "CAN_TLS"
default:
return "INVALID"
}
}

// ContactHeader will be exchanged at first after a TCP connection was
// established. Both entities are sending a ContactHeader and are validating
// the peer's one.
type ContactHeader struct {
Flags ContactFlags
}

// NewContactHeader creates a new ContactHeader with given ContactFlags.
func NewContactHeader(flags ContactFlags) ContactHeader {
return ContactHeader{
Flags: flags,
}
}

func (ch ContactHeader) String() string {
return fmt.Sprintf("ContactHeader(Version=4, Flags=%v)", ch.Flags)
}

// MarshalBinary encodes this ContactHeader into its binary form.
func (ch ContactHeader) MarshalBinary() (data []byte, _ error) {
// magic='dtn!', version=4, flags=flags
data = []byte{0x64, 0x74, 0x6E, 0x21, 0x04, byte(ch.Flags)}
return
}

// UnmarshalBinary decodes a ContactHeader from its binary form.
func (ch *ContactHeader) UnmarshalBinary(data []byte) error {
if len(data) != 6 {
return fmt.Errorf("ContactHeader's length is wrong: %d instead of 6", len(data))
}

if !bytes.Equal(data[:4], []byte("dtn!")) {
return fmt.Errorf("ContactHeader's magic does not match: %x != 'dtn!'", data[:4])
}

if uint8(data[4]) != 4 {
return fmt.Errorf("ContactHeader's version is wrong: %d instead of 4", uint8(data[4]))
}

if cf := ContactFlags(data[5]); cf&contactFlags_INVALID != 0 {
return fmt.Errorf("ContactHeader's flags %x contain invalid flags", cf)
} else {
ch.Flags = cf
}

return nil
}
52 changes: 52 additions & 0 deletions cla/tcpcl/contact_header_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tcpcl

import (
"bytes"
"reflect"
"testing"
)

func TestContactHeaderMarshal(t *testing.T) {
tests := []struct {
contactHeader ContactHeader
expectedData []byte
}{
{NewContactHeader(ContactFlags_NONE), []byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x00}},
{NewContactHeader(ContactFlags_CAN_TLS), []byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x01}},
}

for _, test := range tests {
if data, err := test.contactHeader.MarshalBinary(); err != nil {
t.Fatal(err)
} else if !bytes.Equal(data, test.expectedData) {
t.Fatalf("Data does not match, expected %x and got %x", test.expectedData, data)
}
}
}

func TestContactHeaderUnmarshal(t *testing.T) {
tests := []struct {
data []byte
valid bool
contactHeader ContactHeader
}{
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x00}, true, ContactHeader{Flags: ContactFlags_NONE}},
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x01}, true, ContactHeader{Flags: ContactFlags_CAN_TLS}},
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x04}, false, ContactHeader{}},
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x00, 0x00}, false, ContactHeader{}},
{[]byte{0x64, 0x74, 0x6E, 0x3F, 0x04, 0x00}, false, ContactHeader{}},
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x23, 0x00}, false, ContactHeader{}},
{[]byte{0x64, 0x74, 0x6E, 0x21, 0x04, 0x23}, false, ContactHeader{}},
}

for _, test := range tests {
var ch ContactHeader
if err := ch.UnmarshalBinary(test.data); (err == nil) != test.valid {
t.Fatalf("Error state was not expected; valid := %t, got := %v", test.valid, err)
} else if !test.valid {
continue
} else if !reflect.DeepEqual(test.contactHeader, ch) {
t.Fatalf("ContactHeader does not match, expected %v and got %v", test.contactHeader, ch)
}
}
}

0 comments on commit 3889f27

Please sign in to comment.