99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
// 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, WouldBlock
|
|
}
|
|
// 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, WouldBlock
|
|
}
|