File: frame-reader.go

package info (click to toggle)
golang-github-bifurcation-mint 0.0~git20200214.93c820e-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid
  • size: 632 kB
  • sloc: makefile: 3
file content (98 lines) | stat: -rw-r--r-- 2,278 bytes parent folder | download
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
// Read a generic "framed" packet consisting of a header and a
// This is used for both TLS Records and TLS Handshake Messages
package mint

type framing interface {
	headerLen() int
	defaultReadLen() int
	frameLen(hdr []byte) (int, error)
}

const (
	kFrameReaderHdr  = 0
	kFrameReaderBody = 1
)

type frameNextAction func(f *frameReader) error

type frameReader struct {
	details     framing
	state       uint8
	header      []byte
	body        []byte
	working     []byte
	writeOffset int
	remainder   []byte
}

func newFrameReader(d framing) *frameReader {
	hdr := make([]byte, d.headerLen())
	return &frameReader{
		d,
		kFrameReaderHdr,
		hdr,
		nil,
		hdr,
		0,
		nil,
	}
}

func dup(a []byte) []byte {
	r := make([]byte, len(a))
	copy(r, a)
	return r
}

func (f *frameReader) needed() int {
	tmp := (len(f.working) - f.writeOffset) - len(f.remainder)
	if tmp < 0 {
		return 0
	}
	return tmp
}

func (f *frameReader) addChunk(in []byte) {
	// Append to the buffer.
	logf(logTypeFrameReader, "Appending %v", len(in))
	f.remainder = append(f.remainder, in...)
}

func (f *frameReader) process() (hdr []byte, body []byte, err error) {
	for f.needed() == 0 {
		logf(logTypeFrameReader, "%v bytes needed for next block", len(f.working)-f.writeOffset)
		// Fill out our working block
		copied := copy(f.working[f.writeOffset:], f.remainder)
		f.remainder = f.remainder[copied:]
		f.writeOffset += copied
		if f.writeOffset < len(f.working) {
			logf(logTypeVerbose, "Read would have blocked 1")
			return nil, nil, AlertWouldBlock
		}
		// Reset the write offset, because we are now full.
		f.writeOffset = 0

		// We have read a full frame
		if f.state == kFrameReaderBody {
			logf(logTypeFrameReader, "Returning frame hdr=%#x len=%d buffered=%d", f.header, len(f.body), len(f.remainder))
			f.state = kFrameReaderHdr
			f.working = f.header
			return dup(f.header), dup(f.body), nil
		}

		// We have read the header
		bodyLen, err := f.details.frameLen(f.header)
		if err != nil {
			return nil, nil, err
		}
		logf(logTypeFrameReader, "Processed header, body len = %v", bodyLen)

		f.body = make([]byte, bodyLen)
		f.working = f.body
		f.writeOffset = 0
		f.state = kFrameReaderBody
	}

	logf(logTypeVerbose, "Read would have blocked 2")
	return nil, nil, AlertWouldBlock
}