1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 */
8
9 #include <quic/codec/Types.h>
10
11 #include <quic/QuicException.h>
12
13 namespace quic {
14
LongHeaderInvariant(QuicVersion ver,ConnectionId scid,ConnectionId dcid)15 LongHeaderInvariant::LongHeaderInvariant(
16 QuicVersion ver,
17 ConnectionId scid,
18 ConnectionId dcid)
19 : version(ver), srcConnId(std::move(scid)), dstConnId(std::move(dcid)) {}
20
getHeaderForm(uint8_t headerValue)21 HeaderForm getHeaderForm(uint8_t headerValue) {
22 if (headerValue & kHeaderFormMask) {
23 return HeaderForm::Long;
24 }
25 return HeaderForm::Short;
26 }
27
PacketHeader(ShortHeader && shortHeaderIn)28 PacketHeader::PacketHeader(ShortHeader&& shortHeaderIn)
29 : headerForm_(HeaderForm::Short) {
30 new (&shortHeader) ShortHeader(std::move(shortHeaderIn));
31 }
32
PacketHeader(LongHeader && longHeaderIn)33 PacketHeader::PacketHeader(LongHeader&& longHeaderIn)
34 : headerForm_(HeaderForm::Long) {
35 new (&longHeader) LongHeader(std::move(longHeaderIn));
36 }
37
PacketHeader(const PacketHeader & other)38 PacketHeader::PacketHeader(const PacketHeader& other)
39 : headerForm_(other.headerForm_) {
40 switch (other.headerForm_) {
41 case HeaderForm::Long:
42 new (&longHeader) LongHeader(other.longHeader);
43 break;
44 case HeaderForm::Short:
45 new (&shortHeader) ShortHeader(other.shortHeader);
46 break;
47 }
48 }
49
PacketHeader(PacketHeader && other)50 PacketHeader::PacketHeader(PacketHeader&& other) noexcept
51 : headerForm_(other.headerForm_) {
52 switch (other.headerForm_) {
53 case HeaderForm::Long:
54 new (&longHeader) LongHeader(std::move(other.longHeader));
55 break;
56 case HeaderForm::Short:
57 new (&shortHeader) ShortHeader(std::move(other.shortHeader));
58 break;
59 }
60 }
61
operator =(PacketHeader && other)62 PacketHeader& PacketHeader::operator=(PacketHeader&& other) noexcept {
63 destroyHeader();
64 switch (other.headerForm_) {
65 case HeaderForm::Long:
66 new (&longHeader) LongHeader(std::move(other.longHeader));
67 break;
68 case HeaderForm::Short:
69 new (&shortHeader) ShortHeader(std::move(other.shortHeader));
70 break;
71 }
72 headerForm_ = other.headerForm_;
73 return *this;
74 }
75
operator =(const PacketHeader & other)76 PacketHeader& PacketHeader::operator=(const PacketHeader& other) {
77 destroyHeader();
78 switch (other.headerForm_) {
79 case HeaderForm::Long:
80 new (&longHeader) LongHeader(other.longHeader);
81 break;
82 case HeaderForm::Short:
83 new (&shortHeader) ShortHeader(other.shortHeader);
84 break;
85 }
86 headerForm_ = other.headerForm_;
87 return *this;
88 }
89
~PacketHeader()90 PacketHeader::~PacketHeader() {
91 destroyHeader();
92 }
93
destroyHeader()94 void PacketHeader::destroyHeader() {
95 switch (headerForm_) {
96 case HeaderForm::Long:
97 longHeader.~LongHeader();
98 break;
99 case HeaderForm::Short:
100 shortHeader.~ShortHeader();
101 break;
102 }
103 }
104
asLong()105 LongHeader* PacketHeader::asLong() {
106 switch (headerForm_) {
107 case HeaderForm::Long:
108 return &longHeader;
109 case HeaderForm::Short:
110 return nullptr;
111 default:
112 folly::assume_unreachable();
113 }
114 }
115
asShort()116 ShortHeader* PacketHeader::asShort() {
117 switch (headerForm_) {
118 case HeaderForm::Long:
119 return nullptr;
120 case HeaderForm::Short:
121 return &shortHeader;
122 default:
123 folly::assume_unreachable();
124 }
125 }
126
asLong() const127 const LongHeader* PacketHeader::asLong() const {
128 switch (headerForm_) {
129 case HeaderForm::Long:
130 return &longHeader;
131 case HeaderForm::Short:
132 return nullptr;
133 default:
134 folly::assume_unreachable();
135 }
136 }
137
asShort() const138 const ShortHeader* PacketHeader::asShort() const {
139 switch (headerForm_) {
140 case HeaderForm::Long:
141 return nullptr;
142 case HeaderForm::Short:
143 return &shortHeader;
144 default:
145 folly::assume_unreachable();
146 }
147 }
148
getHeaderForm() const149 HeaderForm PacketHeader::getHeaderForm() const {
150 return headerForm_;
151 }
152
getProtectionType() const153 ProtectionType PacketHeader::getProtectionType() const {
154 switch (headerForm_) {
155 case HeaderForm::Long:
156 return longHeader.getProtectionType();
157 case HeaderForm::Short:
158 return shortHeader.getProtectionType();
159 default:
160 folly::assume_unreachable();
161 }
162 }
163
LongHeader(Types type,LongHeaderInvariant invariant,std::string token)164 LongHeader::LongHeader(
165 Types type,
166 LongHeaderInvariant invariant,
167 std::string token)
168 : longHeaderType_(type),
169 invariant_(std::move(invariant)),
170 token_(std::move(token)) {}
171
LongHeader(Types type,const ConnectionId & srcConnId,const ConnectionId & dstConnId,PacketNum packetNum,QuicVersion version,std::string token)172 LongHeader::LongHeader(
173 Types type,
174 const ConnectionId& srcConnId,
175 const ConnectionId& dstConnId,
176 PacketNum packetNum,
177 QuicVersion version,
178 std::string token)
179 : longHeaderType_(type),
180 invariant_(LongHeaderInvariant(version, srcConnId, dstConnId)),
181 token_(std::move(token)) {
182 setPacketNumber(packetNum);
183 }
184
getHeaderType() const185 LongHeader::Types LongHeader::getHeaderType() const noexcept {
186 return longHeaderType_;
187 }
188
getSourceConnId() const189 const ConnectionId& LongHeader::getSourceConnId() const {
190 return invariant_.srcConnId;
191 }
192
getDestinationConnId() const193 const ConnectionId& LongHeader::getDestinationConnId() const {
194 return invariant_.dstConnId;
195 }
196
getVersion() const197 QuicVersion LongHeader::getVersion() const {
198 return invariant_.version;
199 }
200
hasToken() const201 bool LongHeader::hasToken() const {
202 return !token_.empty();
203 }
204
getToken() const205 const std::string& LongHeader::getToken() const {
206 return token_;
207 }
208
setPacketNumber(PacketNum packetNum)209 void LongHeader::setPacketNumber(PacketNum packetNum) {
210 packetSequenceNum_ = packetNum;
211 }
212
getProtectionType() const213 ProtectionType LongHeader::getProtectionType() const {
214 return longHeaderTypeToProtectionType(getHeaderType());
215 }
216
longHeaderTypeToProtectionType(LongHeader::Types longHeaderType)217 ProtectionType longHeaderTypeToProtectionType(
218 LongHeader::Types longHeaderType) {
219 switch (longHeaderType) {
220 case LongHeader::Types::Initial:
221 case LongHeader::Types::Retry:
222 return ProtectionType::Initial;
223 case LongHeader::Types::Handshake:
224 return ProtectionType::Handshake;
225 case LongHeader::Types::ZeroRtt:
226 return ProtectionType::ZeroRtt;
227 }
228 folly::assume_unreachable();
229 }
230
protectionTypeToPacketNumberSpace(ProtectionType protectionType)231 PacketNumberSpace protectionTypeToPacketNumberSpace(
232 ProtectionType protectionType) {
233 switch (protectionType) {
234 case ProtectionType::Initial:
235 return PacketNumberSpace::Initial;
236 case ProtectionType::Handshake:
237 return PacketNumberSpace::Handshake;
238 case ProtectionType::ZeroRtt:
239 case ProtectionType::KeyPhaseZero:
240 case ProtectionType::KeyPhaseOne:
241 return PacketNumberSpace::AppData;
242 }
243 folly::assume_unreachable();
244 }
245
ShortHeaderInvariant(ConnectionId dcid)246 ShortHeaderInvariant::ShortHeaderInvariant(ConnectionId dcid)
247 : destinationConnId(std::move(dcid)) {}
248
ShortHeader(ProtectionType protectionType,ConnectionId connId,PacketNum packetNum)249 ShortHeader::ShortHeader(
250 ProtectionType protectionType,
251 ConnectionId connId,
252 PacketNum packetNum)
253 : protectionType_(protectionType), connectionId_(std::move(connId)) {
254 if (protectionType_ != ProtectionType::KeyPhaseZero &&
255 protectionType_ != ProtectionType::KeyPhaseOne) {
256 throw QuicInternalException(
257 "bad short header protection type", LocalErrorCode::CODEC_ERROR);
258 }
259 setPacketNumber(packetNum);
260 }
261
ShortHeader(ProtectionType protectionType,ConnectionId connId)262 ShortHeader::ShortHeader(ProtectionType protectionType, ConnectionId connId)
263 : protectionType_(protectionType), connectionId_(std::move(connId)) {
264 if (protectionType_ != ProtectionType::KeyPhaseZero &&
265 protectionType_ != ProtectionType::KeyPhaseOne) {
266 throw QuicInternalException(
267 "bad short header protection type", LocalErrorCode::CODEC_ERROR);
268 }
269 }
270
getProtectionType() const271 ProtectionType ShortHeader::getProtectionType() const {
272 return protectionType_;
273 }
274
getConnectionId() const275 const ConnectionId& ShortHeader::getConnectionId() const {
276 return connectionId_;
277 }
278
setPacketNumber(PacketNum packetNum)279 void ShortHeader::setPacketNumber(PacketNum packetNum) {
280 packetSequenceNum_ = packetNum;
281 }
282
hasDataLength() const283 bool StreamTypeField::hasDataLength() const {
284 return field_ & kDataLengthBit;
285 }
286
hasFin() const287 bool StreamTypeField::hasFin() const {
288 return field_ & kFinBit;
289 }
290
hasOffset() const291 bool StreamTypeField::hasOffset() const {
292 return field_ & kOffsetBit;
293 }
294
fieldValue() const295 uint8_t StreamTypeField::fieldValue() const {
296 return field_;
297 }
298
setFin()299 StreamTypeField::Builder& StreamTypeField::Builder::setFin() {
300 field_ |= StreamTypeField::kFinBit;
301 return *this;
302 }
303
setOffset()304 StreamTypeField::Builder& StreamTypeField::Builder::setOffset() {
305 field_ |= StreamTypeField::kOffsetBit;
306 return *this;
307 }
308
setLength()309 StreamTypeField::Builder& StreamTypeField::Builder::setLength() {
310 field_ |= StreamTypeField::kDataLengthBit;
311 return *this;
312 }
313
build()314 StreamTypeField StreamTypeField::Builder::build() {
315 return StreamTypeField(field_);
316 }
317
getPlaintextToken()318 Buf RetryToken::getPlaintextToken() {
319 // The plaintext token consists of the following:
320 // len(odcid) || odcid || port || ipaddr_len || ipaddr || timestamp
321 auto buf = std::make_unique<folly::IOBuf>();
322 folly::io::Appender appender(buf.get(), 20);
323
324 // Write the odcid length
325 uint8_t odcidLen = originalDstConnId.size();
326 appender.writeBE<uint8_t>(odcidLen);
327
328 // Write the odcid
329 appender.push(originalDstConnId.data(), odcidLen);
330
331 // Write the port
332 appender.writeBE<uint16_t>(clientPort);
333
334 std::string clientIpStr = clientIp.str();
335
336 // Write the ipaddr len
337 appender.writeBE<uint8_t>(clientIpStr.size());
338
339 // Write the ipaddr
340 appender.push((const uint8_t*)clientIpStr.data(), clientIpStr.size());
341
342 // Write the timestamp
343 appender.writeBE<uint64_t>(timestampInMs);
344
345 return buf;
346 }
347
toString(PacketNumberSpace pnSpace)348 std::string toString(PacketNumberSpace pnSpace) {
349 switch (pnSpace) {
350 case PacketNumberSpace::Initial:
351 return "InitialSpace";
352 case PacketNumberSpace::Handshake:
353 return "HandshakeSpace";
354 case PacketNumberSpace::AppData:
355 return "AppDataSpace";
356 }
357 CHECK(false) << "Unknown packet number space";
358 folly::assume_unreachable();
359 }
360
toString(ProtectionType protectionType)361 std::string toString(ProtectionType protectionType) {
362 switch (protectionType) {
363 case ProtectionType::Initial:
364 return "Initial";
365 case ProtectionType::Handshake:
366 return "Handshake";
367 case ProtectionType::ZeroRtt:
368 return "ZeroRtt";
369 case ProtectionType::KeyPhaseZero:
370 return "KeyPhaseZero";
371 case ProtectionType::KeyPhaseOne:
372 return "KeyPhaseOne";
373 }
374 CHECK(false) << "Unknown protection type";
375 folly::assume_unreachable();
376 }
377
toString(FrameType frame)378 std::string toString(FrameType frame) {
379 switch (frame) {
380 case FrameType::PADDING:
381 return "PADDING";
382 case FrameType::PING:
383 return "PING";
384 case FrameType::ACK:
385 return "ACK";
386 case FrameType::ACK_ECN:
387 return "ACK_ECN";
388 case FrameType::RST_STREAM:
389 return "RST_STREAM";
390 case FrameType::STOP_SENDING:
391 return "STOP_SENDING";
392 case FrameType::CRYPTO_FRAME:
393 return "CRYPTO_FRAME";
394 case FrameType::NEW_TOKEN:
395 return "NEW_TOKEN";
396 case FrameType::STREAM:
397 case FrameType::STREAM_FIN:
398 case FrameType::STREAM_LEN:
399 case FrameType::STREAM_LEN_FIN:
400 case FrameType::STREAM_OFF:
401 case FrameType::STREAM_OFF_FIN:
402 case FrameType::STREAM_OFF_LEN:
403 case FrameType::STREAM_OFF_LEN_FIN:
404 return "STREAM";
405 case FrameType::MAX_DATA:
406 return "MAX_DATA";
407 case FrameType::MAX_STREAM_DATA:
408 return "MAX_STREAM_DATA";
409 case FrameType::MAX_STREAMS_BIDI:
410 return "MAX_STREAMS_BIDI";
411 case FrameType::MAX_STREAMS_UNI:
412 return "MAX_STREAMS_UNI";
413 case FrameType::DATA_BLOCKED:
414 return "DATA_BLOCKED";
415 case FrameType::STREAM_DATA_BLOCKED:
416 return "STREAM_DATA_BLOCKED";
417 case FrameType::STREAMS_BLOCKED_BIDI:
418 return "STREAMS_BLOCKED_BIDI";
419 case FrameType::STREAMS_BLOCKED_UNI:
420 return "STREAMS_BLOCKED_UNI";
421 case FrameType::NEW_CONNECTION_ID:
422 return "NEW_CONNECTION_ID";
423 case FrameType::RETIRE_CONNECTION_ID:
424 return "RETIRE_CONNECTION_ID";
425 case FrameType::PATH_CHALLENGE:
426 return "PATH_CHALLENGE";
427 case FrameType::PATH_RESPONSE:
428 return "PATH_RESPONSE";
429 case FrameType::CONNECTION_CLOSE:
430 return "CONNECTION_CLOSE";
431 case FrameType::CONNECTION_CLOSE_APP_ERR:
432 return "APPLICATION_CLOSE";
433 case FrameType::HANDSHAKE_DONE:
434 return "HANDSHAKE_DONE";
435 case FrameType::DATAGRAM:
436 case FrameType::DATAGRAM_LEN:
437 return "DATAGRAM";
438 case FrameType::KNOB:
439 return "KNOB";
440 case FrameType::ACK_FREQUENCY:
441 return "ACK_FREQUENCY";
442 }
443 LOG(WARNING) << "toString has unhandled frame type";
444 return "UNKNOWN";
445 }
446
toString(QuicVersion version)447 std::string toString(QuicVersion version) {
448 switch (version) {
449 case QuicVersion::VERSION_NEGOTIATION:
450 return "VERSION_NEGOTIATION";
451 case QuicVersion::MVFST:
452 return "MVFST";
453 case QuicVersion::QUIC_V1:
454 return "QUIC_V1";
455 case QuicVersion::QUIC_DRAFT:
456 return "QUIC_DRAFT";
457 case QuicVersion::QUIC_DRAFT_LEGACY:
458 return "QUIC_DRAFT_LEGACY";
459 case QuicVersion::MVFST_EXPERIMENTAL:
460 return "MVFST_EXPERIMENTAL";
461 case QuicVersion::MVFST_ALIAS:
462 return "MVFST_ALIAS";
463 case QuicVersion::MVFST_INVALID:
464 return "MVFST_INVALID";
465 }
466 LOG(WARNING) << "toString has unhandled version type";
467 return "UNKNOWN";
468 }
469
toString(LongHeader::Types type)470 std::string toString(LongHeader::Types type) {
471 switch (type) {
472 case LongHeader::Types::Initial:
473 return "INITIAL";
474 case LongHeader::Types::Retry:
475 return "RETRY";
476 case LongHeader::Types::Handshake:
477 return "HANDSHAKE";
478 case LongHeader::Types::ZeroRtt:
479 return "ZERORTT";
480 }
481 LOG(WARNING) << "toString has unhandled long header type";
482 return "UNKNOWN";
483 }
484 } // namespace quic
485