1package wire
2
3import (
4	"bytes"
5	"io"
6
7	"github.com/lucas-clemente/quic-go/internal/protocol"
8	"github.com/lucas-clemente/quic-go/quicvarint"
9)
10
11// A DatagramFrame is a DATAGRAM frame
12type DatagramFrame struct {
13	DataLenPresent bool
14	Data           []byte
15}
16
17func parseDatagramFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DatagramFrame, error) {
18	typeByte, err := r.ReadByte()
19	if err != nil {
20		return nil, err
21	}
22
23	f := &DatagramFrame{}
24	f.DataLenPresent = typeByte&0x1 > 0
25
26	var length uint64
27	if f.DataLenPresent {
28		var err error
29		len, err := quicvarint.Read(r)
30		if err != nil {
31			return nil, err
32		}
33		if len > uint64(r.Len()) {
34			return nil, io.EOF
35		}
36		length = len
37	} else {
38		length = uint64(r.Len())
39	}
40	f.Data = make([]byte, length)
41	if _, err := io.ReadFull(r, f.Data); err != nil {
42		return nil, err
43	}
44	return f, nil
45}
46
47func (f *DatagramFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
48	typeByte := uint8(0x30)
49	if f.DataLenPresent {
50		typeByte ^= 0x1
51	}
52	b.WriteByte(typeByte)
53	if f.DataLenPresent {
54		quicvarint.Write(b, uint64(len(f.Data)))
55	}
56	b.Write(f.Data)
57	return nil
58}
59
60// MaxDataLen returns the maximum data length
61func (f *DatagramFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
62	headerLen := protocol.ByteCount(1)
63	if f.DataLenPresent {
64		// pretend that the data size will be 1 bytes
65		// if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
66		headerLen++
67	}
68	if headerLen > maxSize {
69		return 0
70	}
71	maxDataLen := maxSize - headerLen
72	if f.DataLenPresent && quicvarint.Len(uint64(maxDataLen)) != 1 {
73		maxDataLen--
74	}
75	return maxDataLen
76}
77
78// Length of a written frame
79func (f *DatagramFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
80	length := 1 + protocol.ByteCount(len(f.Data))
81	if f.DataLenPresent {
82		length += quicvarint.Len(uint64(len(f.Data)))
83	}
84	return length
85}
86