1
2
3
4
5
6
7 package quic
8
9 import (
10 "encoding/binary"
11 "net/netip"
12 "time"
13 )
14
15
16
17 type transportParameters struct {
18 originalDstConnID []byte
19 maxIdleTimeout time.Duration
20 statelessResetToken []byte
21 maxUDPPayloadSize int64
22 initialMaxData int64
23 initialMaxStreamDataBidiLocal int64
24 initialMaxStreamDataBidiRemote int64
25 initialMaxStreamDataUni int64
26 initialMaxStreamsBidi int64
27 initialMaxStreamsUni int64
28 ackDelayExponent int8
29 maxAckDelay time.Duration
30 disableActiveMigration bool
31 preferredAddrV4 netip.AddrPort
32 preferredAddrV6 netip.AddrPort
33 preferredAddrConnID []byte
34 preferredAddrResetToken []byte
35 activeConnIDLimit int64
36 initialSrcConnID []byte
37 retrySrcConnID []byte
38 }
39
40 const (
41 defaultParamMaxUDPPayloadSize = 65527
42 defaultParamAckDelayExponent = 3
43 defaultParamMaxAckDelayMilliseconds = 25
44 defaultParamActiveConnIDLimit = 2
45 )
46
47
48 func defaultTransportParameters() transportParameters {
49 return transportParameters{
50 maxUDPPayloadSize: defaultParamMaxUDPPayloadSize,
51 ackDelayExponent: defaultParamAckDelayExponent,
52 maxAckDelay: defaultParamMaxAckDelayMilliseconds * time.Millisecond,
53 activeConnIDLimit: defaultParamActiveConnIDLimit,
54 }
55 }
56
57 const (
58 paramOriginalDestinationConnectionID = 0x00
59 paramMaxIdleTimeout = 0x01
60 paramStatelessResetToken = 0x02
61 paramMaxUDPPayloadSize = 0x03
62 paramInitialMaxData = 0x04
63 paramInitialMaxStreamDataBidiLocal = 0x05
64 paramInitialMaxStreamDataBidiRemote = 0x06
65 paramInitialMaxStreamDataUni = 0x07
66 paramInitialMaxStreamsBidi = 0x08
67 paramInitialMaxStreamsUni = 0x09
68 paramAckDelayExponent = 0x0a
69 paramMaxAckDelay = 0x0b
70 paramDisableActiveMigration = 0x0c
71 paramPreferredAddress = 0x0d
72 paramActiveConnectionIDLimit = 0x0e
73 paramInitialSourceConnectionID = 0x0f
74 paramRetrySourceConnectionID = 0x10
75 )
76
77 func marshalTransportParameters(p transportParameters) []byte {
78 var b []byte
79 if v := p.originalDstConnID; v != nil {
80 b = appendVarint(b, paramOriginalDestinationConnectionID)
81 b = appendVarintBytes(b, v)
82 }
83 if v := uint64(p.maxIdleTimeout / time.Millisecond); v != 0 {
84 b = appendVarint(b, paramMaxIdleTimeout)
85 b = appendVarint(b, uint64(sizeVarint(v)))
86 b = appendVarint(b, uint64(v))
87 }
88 if v := p.statelessResetToken; v != nil {
89 b = appendVarint(b, paramStatelessResetToken)
90 b = appendVarintBytes(b, v)
91 }
92 if v := p.maxUDPPayloadSize; v != defaultParamMaxUDPPayloadSize {
93 b = appendVarint(b, paramMaxUDPPayloadSize)
94 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
95 b = appendVarint(b, uint64(v))
96 }
97 if v := p.initialMaxData; v != 0 {
98 b = appendVarint(b, paramInitialMaxData)
99 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
100 b = appendVarint(b, uint64(v))
101 }
102 if v := p.initialMaxStreamDataBidiLocal; v != 0 {
103 b = appendVarint(b, paramInitialMaxStreamDataBidiLocal)
104 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
105 b = appendVarint(b, uint64(v))
106 }
107 if v := p.initialMaxStreamDataBidiRemote; v != 0 {
108 b = appendVarint(b, paramInitialMaxStreamDataBidiRemote)
109 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
110 b = appendVarint(b, uint64(v))
111 }
112 if v := p.initialMaxStreamDataUni; v != 0 {
113 b = appendVarint(b, paramInitialMaxStreamDataUni)
114 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
115 b = appendVarint(b, uint64(v))
116 }
117 if v := p.initialMaxStreamsBidi; v != 0 {
118 b = appendVarint(b, paramInitialMaxStreamsBidi)
119 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
120 b = appendVarint(b, uint64(v))
121 }
122 if v := p.initialMaxStreamsUni; v != 0 {
123 b = appendVarint(b, paramInitialMaxStreamsUni)
124 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
125 b = appendVarint(b, uint64(v))
126 }
127 if v := p.ackDelayExponent; v != defaultParamAckDelayExponent {
128 b = appendVarint(b, paramAckDelayExponent)
129 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
130 b = appendVarint(b, uint64(v))
131 }
132 if v := uint64(p.maxAckDelay / time.Millisecond); v != defaultParamMaxAckDelayMilliseconds {
133 b = appendVarint(b, paramMaxAckDelay)
134 b = appendVarint(b, uint64(sizeVarint(v)))
135 b = appendVarint(b, v)
136 }
137 if p.disableActiveMigration {
138 b = appendVarint(b, paramDisableActiveMigration)
139 b = append(b, 0)
140 }
141 if p.preferredAddrConnID != nil {
142 b = append(b, paramPreferredAddress)
143 b = appendVarint(b, uint64(4+2+16+2+1+len(p.preferredAddrConnID)+16))
144 b = append(b, p.preferredAddrV4.Addr().AsSlice()...)
145 b = binary.BigEndian.AppendUint16(b, p.preferredAddrV4.Port())
146 b = append(b, p.preferredAddrV6.Addr().AsSlice()...)
147 b = binary.BigEndian.AppendUint16(b, p.preferredAddrV6.Port())
148 b = appendUint8Bytes(b, p.preferredAddrConnID)
149 b = append(b, p.preferredAddrResetToken...)
150 }
151 if v := p.activeConnIDLimit; v != defaultParamActiveConnIDLimit {
152 b = appendVarint(b, paramActiveConnectionIDLimit)
153 b = appendVarint(b, uint64(sizeVarint(uint64(v))))
154 b = appendVarint(b, uint64(v))
155 }
156 if v := p.initialSrcConnID; v != nil {
157 b = appendVarint(b, paramInitialSourceConnectionID)
158 b = appendVarintBytes(b, v)
159 }
160 if v := p.retrySrcConnID; v != nil {
161 b = appendVarint(b, paramRetrySourceConnectionID)
162 b = appendVarintBytes(b, v)
163 }
164 return b
165 }
166
167 func unmarshalTransportParams(params []byte) (transportParameters, error) {
168 p := defaultTransportParameters()
169 for len(params) > 0 {
170 id, n := consumeVarint(params)
171 if n < 0 {
172 return p, localTransportError{code: errTransportParameter}
173 }
174 params = params[n:]
175 val, n := consumeVarintBytes(params)
176 if n < 0 {
177 return p, localTransportError{code: errTransportParameter}
178 }
179 params = params[n:]
180 n = 0
181 switch id {
182 case paramOriginalDestinationConnectionID:
183 p.originalDstConnID = val
184 n = len(val)
185 case paramMaxIdleTimeout:
186 var v uint64
187 v, n = consumeVarint(val)
188
189
190 if v > 1<<32 {
191 v = 0
192 }
193 p.maxIdleTimeout = time.Duration(v) * time.Millisecond
194 case paramStatelessResetToken:
195 if len(val) != 16 {
196 return p, localTransportError{code: errTransportParameter}
197 }
198 p.statelessResetToken = val
199 n = 16
200 case paramMaxUDPPayloadSize:
201 p.maxUDPPayloadSize, n = consumeVarintInt64(val)
202 if p.maxUDPPayloadSize < 1200 {
203 return p, localTransportError{code: errTransportParameter}
204 }
205 case paramInitialMaxData:
206 p.initialMaxData, n = consumeVarintInt64(val)
207 case paramInitialMaxStreamDataBidiLocal:
208 p.initialMaxStreamDataBidiLocal, n = consumeVarintInt64(val)
209 case paramInitialMaxStreamDataBidiRemote:
210 p.initialMaxStreamDataBidiRemote, n = consumeVarintInt64(val)
211 case paramInitialMaxStreamDataUni:
212 p.initialMaxStreamDataUni, n = consumeVarintInt64(val)
213 case paramInitialMaxStreamsBidi:
214 p.initialMaxStreamsBidi, n = consumeVarintInt64(val)
215 if p.initialMaxStreamsBidi > maxStreamsLimit {
216 return p, localTransportError{code: errTransportParameter}
217 }
218 case paramInitialMaxStreamsUni:
219 p.initialMaxStreamsUni, n = consumeVarintInt64(val)
220 if p.initialMaxStreamsUni > maxStreamsLimit {
221 return p, localTransportError{code: errTransportParameter}
222 }
223 case paramAckDelayExponent:
224 var v uint64
225 v, n = consumeVarint(val)
226 if v > 20 {
227 return p, localTransportError{code: errTransportParameter}
228 }
229 p.ackDelayExponent = int8(v)
230 case paramMaxAckDelay:
231 var v uint64
232 v, n = consumeVarint(val)
233 if v >= 1<<14 {
234 return p, localTransportError{code: errTransportParameter}
235 }
236 p.maxAckDelay = time.Duration(v) * time.Millisecond
237 case paramDisableActiveMigration:
238 p.disableActiveMigration = true
239 case paramPreferredAddress:
240 if len(val) < 4+2+16+2+1 {
241 return p, localTransportError{code: errTransportParameter}
242 }
243 p.preferredAddrV4 = netip.AddrPortFrom(
244 netip.AddrFrom4(*(*[4]byte)(val[:4])),
245 binary.BigEndian.Uint16(val[4:][:2]),
246 )
247 val = val[4+2:]
248 p.preferredAddrV6 = netip.AddrPortFrom(
249 netip.AddrFrom16(*(*[16]byte)(val[:16])),
250 binary.BigEndian.Uint16(val[16:][:2]),
251 )
252 val = val[16+2:]
253 var nn int
254 p.preferredAddrConnID, nn = consumeUint8Bytes(val)
255 if nn < 0 {
256 return p, localTransportError{code: errTransportParameter}
257 }
258 val = val[nn:]
259 if len(val) != 16 {
260 return p, localTransportError{code: errTransportParameter}
261 }
262 p.preferredAddrResetToken = val
263 val = nil
264 case paramActiveConnectionIDLimit:
265 p.activeConnIDLimit, n = consumeVarintInt64(val)
266 if p.activeConnIDLimit < 2 {
267 return p, localTransportError{code: errTransportParameter}
268 }
269 case paramInitialSourceConnectionID:
270 p.initialSrcConnID = val
271 n = len(val)
272 case paramRetrySourceConnectionID:
273 p.retrySrcConnID = val
274 n = len(val)
275 default:
276 n = len(val)
277 }
278 if n != len(val) {
279 return p, localTransportError{code: errTransportParameter}
280 }
281 }
282 return p, nil
283 }
284
View as plain text