1package quic
2
3import (
4	"fmt"
5
6	"github.com/lucas-clemente/quic-go/internal/protocol"
7	"github.com/lucas-clemente/quic-go/internal/wire"
8)
9
10type retransmissionQueue struct {
11	initial           []wire.Frame
12	initialCryptoData []*wire.CryptoFrame
13
14	handshake           []wire.Frame
15	handshakeCryptoData []*wire.CryptoFrame
16
17	appData []wire.Frame
18
19	version protocol.VersionNumber
20}
21
22func newRetransmissionQueue(ver protocol.VersionNumber) *retransmissionQueue {
23	return &retransmissionQueue{version: ver}
24}
25
26func (q *retransmissionQueue) AddInitial(f wire.Frame) {
27	if cf, ok := f.(*wire.CryptoFrame); ok {
28		q.initialCryptoData = append(q.initialCryptoData, cf)
29		return
30	}
31	q.initial = append(q.initial, f)
32}
33
34func (q *retransmissionQueue) AddHandshake(f wire.Frame) {
35	if cf, ok := f.(*wire.CryptoFrame); ok {
36		q.handshakeCryptoData = append(q.handshakeCryptoData, cf)
37		return
38	}
39	q.handshake = append(q.handshake, f)
40}
41
42func (q *retransmissionQueue) HasInitialData() bool {
43	return len(q.initialCryptoData) > 0 || len(q.initial) > 0
44}
45
46func (q *retransmissionQueue) HasHandshakeData() bool {
47	return len(q.handshakeCryptoData) > 0 || len(q.handshake) > 0
48}
49
50func (q *retransmissionQueue) HasAppData() bool {
51	return len(q.appData) > 0
52}
53
54func (q *retransmissionQueue) AddAppData(f wire.Frame) {
55	if _, ok := f.(*wire.StreamFrame); ok {
56		panic("STREAM frames are handled with their respective streams.")
57	}
58	q.appData = append(q.appData, f)
59}
60
61func (q *retransmissionQueue) GetInitialFrame(maxLen protocol.ByteCount) wire.Frame {
62	if len(q.initialCryptoData) > 0 {
63		f := q.initialCryptoData[0]
64		newFrame, needsSplit := f.MaybeSplitOffFrame(maxLen, q.version)
65		if newFrame == nil && !needsSplit { // the whole frame fits
66			q.initialCryptoData = q.initialCryptoData[1:]
67			return f
68		}
69		if newFrame != nil { // frame was split. Leave the original frame in the queue.
70			return newFrame
71		}
72	}
73	if len(q.initial) == 0 {
74		return nil
75	}
76	f := q.initial[0]
77	if f.Length(q.version) > maxLen {
78		return nil
79	}
80	q.initial = q.initial[1:]
81	return f
82}
83
84func (q *retransmissionQueue) GetHandshakeFrame(maxLen protocol.ByteCount) wire.Frame {
85	if len(q.handshakeCryptoData) > 0 {
86		f := q.handshakeCryptoData[0]
87		newFrame, needsSplit := f.MaybeSplitOffFrame(maxLen, q.version)
88		if newFrame == nil && !needsSplit { // the whole frame fits
89			q.handshakeCryptoData = q.handshakeCryptoData[1:]
90			return f
91		}
92		if newFrame != nil { // frame was split. Leave the original frame in the queue.
93			return newFrame
94		}
95	}
96	if len(q.handshake) == 0 {
97		return nil
98	}
99	f := q.handshake[0]
100	if f.Length(q.version) > maxLen {
101		return nil
102	}
103	q.handshake = q.handshake[1:]
104	return f
105}
106
107func (q *retransmissionQueue) GetAppDataFrame(maxLen protocol.ByteCount) wire.Frame {
108	if len(q.appData) == 0 {
109		return nil
110	}
111	f := q.appData[0]
112	if f.Length(q.version) > maxLen {
113		return nil
114	}
115	q.appData = q.appData[1:]
116	return f
117}
118
119func (q *retransmissionQueue) DropPackets(encLevel protocol.EncryptionLevel) {
120	//nolint:exhaustive // Can only drop Initial and Handshake packet number space.
121	switch encLevel {
122	case protocol.EncryptionInitial:
123		q.initial = nil
124		q.initialCryptoData = nil
125	case protocol.EncryptionHandshake:
126		q.handshake = nil
127		q.handshakeCryptoData = nil
128	default:
129		panic(fmt.Sprintf("unexpected encryption level: %s", encLevel))
130	}
131}
132