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