This repository has been archived by the owner on May 9, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
header.go
127 lines (103 loc) · 2.84 KB
/
header.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package fmtp
import (
"fmt"
"encoding/binary"
"github.com/pkg/errors"
)
const (
// values indicated in the specification
// these are correct for v1 and v2 of the specification document
version2 = 2
reserved2 = 0
// length of a header field in bytes(3*uint8 + 1*uint16)
headerLen = 5
// maxLength that can be indicated in a header, as limited by the size of an uint16
maxLength = 2<<15 - 1 // 65535 is the max length
// MaxBodyLen is the maximum body len in bytes
MaxBodyLen = maxLength - headerLen // 65530 is the max body length
// CompatBodyLen is the minimum size that shall be accepted by FMTP implementations
CompatBodyLen = 10240
maxCompatLen = CompatBodyLen + headerLen
)
// header is a FMTP's message Header field
type header struct {
// version indicated the header version.
version uint8
// reserved field is an internal value
reserved uint8
// length indicates the combined length in bytes of the Header and Body
length uint16
// typ indicates the message type that is being transferred
typ Typ
}
func (h *header) Check() error {
if h == nil {
return nil
}
if h.length < headerLen {
return errors.New("header.Check: error, indicated length cannot be smaller than nominal header length")
}
return nil
}
// String prints the header
func (h *header) String() string {
return fmt.Sprintf("Version:\t%d\nReserved:\t%d\nLength:\t%d bytes\n\tTyp:\t\t%d\n", h.version, h.reserved, h.length, h.typ)
}
// MarshalBinary marshals a header into binary form
func (h *header) MarshalBinary() ([]byte, error) {
// Check
err := h.Check()
if err != nil {
return nil, err
}
// Get the length in binary
lenBuf := make([]byte, 2)
binary.BigEndian.PutUint16(lenBuf, h.length)
// Now create the byte slice
out := []byte{
byte(h.version),
byte(h.reserved),
byte(lenBuf[0]),
byte(lenBuf[1]),
byte(h.typ),
}
return out, nil
}
func (h *header) UnmarshalBinary(b []byte) error {
if len(b) != headerLen {
return errors.Errorf("UnmarshalBinary: expected %d bytes, got %d", headerLen, len(b))
}
// Extract length
length := binary.BigEndian.Uint16(b[2:4])
if length > maxLength {
return errors.New("UnmarshalBinary: indicated length larger than max length")
} else if length < headerLen {
return errors.New("UnmarshalBinary: indicated length smaller than nominal header length")
}
// Assign
h.version = b[0]
h.reserved = b[1]
h.length = uint16(length)
h.typ = Typ(b[4])
return nil
}
// newHeader creates a new header in version 2.0
func newHeader(typ Typ) *header {
return &header{
version: version2,
reserved: reserved2,
typ: typ,
}
}
// setLength sets the header length
func (h *header) setBodyLen(bodyLen uint16) {
h.length = headerLen + bodyLen
}
// bodyLen returns the body length
// if no body is here
func (h *header) bodyLen() int {
if h.length == 0 {
return 0
}
return int(h.length) - headerLen
}