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/QuicWriteCodec.h>
10
11 #include <algorithm>
12
13 #include <quic/QuicConstants.h>
14 #include <quic/QuicException.h>
15 #include <quic/codec/QuicInteger.h>
16
17 namespace {
18
19 bool packetSpaceCheck(uint64_t limit, size_t require);
20
21 /**
22 * A helper function to check if there are enough space to write in the packet.
23 * Return: true if there is enough space, false otherwise
24 */
packetSpaceCheck(uint64_t limit,size_t require)25 bool packetSpaceCheck(uint64_t limit, size_t require) {
26 return (folly::to<uint64_t>(require) <= limit);
27 }
28 } // namespace
29
30 namespace quic {
31
writeStreamFrameHeader(PacketBuilderInterface & builder,StreamId id,uint64_t offset,uint64_t writeBufferLen,uint64_t flowControlLen,bool fin,folly::Optional<bool> skipLenHint)32 folly::Optional<uint64_t> writeStreamFrameHeader(
33 PacketBuilderInterface& builder,
34 StreamId id,
35 uint64_t offset,
36 uint64_t writeBufferLen,
37 uint64_t flowControlLen,
38 bool fin,
39 folly::Optional<bool> skipLenHint) {
40 if (builder.remainingSpaceInPkt() == 0) {
41 return folly::none;
42 }
43 if (writeBufferLen == 0 && !fin) {
44 throw QuicInternalException(
45 "No data or fin supplied when writing stream.",
46 LocalErrorCode::INTERNAL_ERROR);
47 }
48 StreamTypeField::Builder streamTypeBuilder;
49 QuicInteger idInt(id);
50 // First account for the things that are non-optional: frame type and stream
51 // id.
52 uint64_t headerSize = sizeof(uint8_t) + idInt.getSize();
53 if (builder.remainingSpaceInPkt() < headerSize) {
54 VLOG(4) << "No space in packet for stream header. stream=" << id
55 << " remaining=" << builder.remainingSpaceInPkt();
56 return folly::none;
57 }
58 QuicInteger offsetInt(offset);
59 if (offset != 0) {
60 streamTypeBuilder.setOffset();
61 headerSize += offsetInt.getSize();
62 }
63 // Next we have to deal with the data length. This is trickier. The length of
64 // data we are able to send depends on 3 things: how much we have in the
65 // buffer, how much flow control we have, and the remaining size in the
66 // packet. If the amount we want to send is >= the remaining packet size after
67 // the header so far we can omit the length field and consume the rest of the
68 // packet. If it is not then we need to use the minimal varint encoding
69 // possible to avoid sending not-full packets.
70 // Note: we don't bother with one potential optimization, which is writing
71 // a zero length fin-only stream frame and omitting the length field.
72 uint64_t dataLen = std::min(writeBufferLen, flowControlLen);
73 uint64_t dataLenLen = 0;
74 bool shouldSkipLengthField;
75 if (skipLenHint) {
76 shouldSkipLengthField = *skipLenHint;
77 } else {
78 // Check if we can fill the entire packet with the rest of this stream frame
79 shouldSkipLengthField =
80 dataLen > 0 && dataLen >= builder.remainingSpaceInPkt() - headerSize;
81 }
82 // At most we can write the minimal between data length and what the packet
83 // builder allows us to write.
84 dataLen = std::min(dataLen, builder.remainingSpaceInPkt() - headerSize);
85 if (!shouldSkipLengthField) {
86 if (dataLen <= kOneByteLimit - 1) {
87 dataLenLen = 1;
88 } else if (dataLen <= kTwoByteLimit - 2) {
89 dataLenLen = 2;
90 } else if (dataLen <= kFourByteLimit - 4) {
91 dataLenLen = 4;
92 } else if (dataLen <= kEightByteLimit - 8) {
93 dataLenLen = 8;
94 } else {
95 // This should never really happen as dataLen is bounded by the remaining
96 // space in the packet which should be << kEightByteLimit.
97 throw QuicInternalException(
98 "Stream frame length too large.", LocalErrorCode::INTERNAL_ERROR);
99 }
100 }
101 if (dataLenLen > 0) {
102 if (dataLen != 0 &&
103 headerSize + dataLenLen >= builder.remainingSpaceInPkt()) {
104 VLOG(4) << "No space in packet for stream header. stream=" << id
105 << " remaining=" << builder.remainingSpaceInPkt();
106 return folly::none;
107 }
108 // We have to encode the actual data length in the header.
109 headerSize += dataLenLen;
110 if (builder.remainingSpaceInPkt() < dataLen + headerSize) {
111 dataLen = builder.remainingSpaceInPkt() - headerSize;
112 }
113 }
114 bool shouldSetFin = fin && dataLen == writeBufferLen;
115 if (dataLen == 0 && !shouldSetFin) {
116 // This would be an empty non-fin stream frame.
117 return folly::none;
118 }
119 if (builder.remainingSpaceInPkt() < headerSize) {
120 VLOG(4) << "No space in packet for stream header. stream=" << id
121 << " remaining=" << builder.remainingSpaceInPkt();
122 return folly::none;
123 }
124
125 // Done with the accounting, set the bits and write the actual frame header.
126 if (dataLenLen > 0) {
127 streamTypeBuilder.setLength();
128 }
129 if (shouldSetFin) {
130 streamTypeBuilder.setFin();
131 }
132 auto streamType = streamTypeBuilder.build();
133 builder.writeBE(streamType.fieldValue());
134 builder.write(idInt);
135 if (offset != 0) {
136 builder.write(offsetInt);
137 }
138 if (dataLenLen > 0) {
139 builder.write(QuicInteger(dataLen));
140 }
141 builder.appendFrame(
142 WriteStreamFrame(id, offset, dataLen, streamType.hasFin()));
143 DCHECK(dataLen <= builder.remainingSpaceInPkt());
144 return folly::make_optional(dataLen);
145 }
146
writeStreamFrameData(PacketBuilderInterface & builder,const BufQueue & writeBuffer,uint64_t dataLen)147 void writeStreamFrameData(
148 PacketBuilderInterface& builder,
149 const BufQueue& writeBuffer,
150 uint64_t dataLen) {
151 if (dataLen > 0) {
152 builder.insert(writeBuffer, dataLen);
153 }
154 }
155
writeStreamFrameData(PacketBuilderInterface & builder,Buf writeBuffer,uint64_t dataLen)156 void writeStreamFrameData(
157 PacketBuilderInterface& builder,
158 Buf writeBuffer,
159 uint64_t dataLen) {
160 if (dataLen > 0) {
161 builder.insert(std::move(writeBuffer), dataLen);
162 }
163 }
164
writeCryptoFrame(uint64_t offsetIn,const BufQueue & data,PacketBuilderInterface & builder)165 folly::Optional<WriteCryptoFrame> writeCryptoFrame(
166 uint64_t offsetIn,
167 const BufQueue& data,
168 PacketBuilderInterface& builder) {
169 uint64_t spaceLeftInPkt = builder.remainingSpaceInPkt();
170 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::CRYPTO_FRAME));
171 QuicInteger offsetInteger(offsetIn);
172
173 size_t lengthBytes = 2;
174 size_t cryptoFrameHeaderSize =
175 intFrameType.getSize() + offsetInteger.getSize() + lengthBytes;
176
177 if (spaceLeftInPkt <= cryptoFrameHeaderSize) {
178 VLOG(3) << "No space left in packet to write cryptoFrame header of size: "
179 << cryptoFrameHeaderSize << ", space left=" << spaceLeftInPkt;
180 return folly::none;
181 }
182 size_t spaceRemaining = spaceLeftInPkt - cryptoFrameHeaderSize;
183 size_t dataLength = data.chainLength();
184 size_t writableData = std::min(dataLength, spaceRemaining);
185 QuicInteger lengthVarInt(writableData);
186
187 if (lengthVarInt.getSize() > lengthBytes) {
188 throw QuicInternalException(
189 std::string("Length bytes representation"),
190 LocalErrorCode::CODEC_ERROR);
191 }
192 builder.write(intFrameType);
193 builder.write(offsetInteger);
194 builder.write(lengthVarInt);
195 builder.insert(data, writableData);
196 builder.appendFrame(WriteCryptoFrame(offsetIn, lengthVarInt.getValue()));
197 return WriteCryptoFrame(offsetIn, lengthVarInt.getValue());
198 }
199
200 /*
201 * This function will fill the parameter ack frame with ack blocks from the
202 * parameter ackBlocks until it runs out of space (bytesLimit). The largest
203 * ack block should have been inserted by the caller.
204 */
fillFrameWithAckBlocks(const AckBlocks & ackBlocks,WriteAckFrame & ackFrame,uint64_t bytesLimit)205 static size_t fillFrameWithAckBlocks(
206 const AckBlocks& ackBlocks,
207 WriteAckFrame& ackFrame,
208 uint64_t bytesLimit) {
209 PacketNum currentSeqNum = ackBlocks.crbegin()->start;
210
211 // starts off with 0 which is what we assumed the initial ack block to be for
212 // the largest acked.
213 size_t numAdditionalAckBlocks = 0;
214 size_t previousNumAckBlocks = 0;
215
216 // Skip the largest, as it has already been emplaced.
217 for (auto blockItr = ackBlocks.crbegin() + 1; blockItr != ackBlocks.crend();
218 ++blockItr) {
219 const auto& currBlock = *blockItr;
220 // These must be true because of the properties of the interval set.
221 CHECK_GE(currentSeqNum, currBlock.end + 2);
222 PacketNum gap = currentSeqNum - currBlock.end - 2;
223 PacketNum currBlockLen = currBlock.end - currBlock.start;
224
225 // TODO this is still extra work, as we end up duplicating these
226 // calculations in the caller, we could store the results so they
227 // can be reused by the caller when writing the frame.
228 size_t gapSize = getQuicIntegerSizeThrows(gap);
229 size_t currBlockLenSize = getQuicIntegerSizeThrows(currBlockLen);
230 size_t numAdditionalAckBlocksSize =
231 getQuicIntegerSizeThrows(numAdditionalAckBlocks + 1);
232 size_t previousNumAckBlocksSize =
233 getQuicIntegerSizeThrows(previousNumAckBlocks);
234
235 size_t additionalSize = gapSize + currBlockLenSize +
236 (numAdditionalAckBlocksSize - previousNumAckBlocksSize);
237 if (bytesLimit < additionalSize) {
238 break;
239 }
240 numAdditionalAckBlocks++;
241 bytesLimit -= additionalSize;
242 previousNumAckBlocks = numAdditionalAckBlocks;
243 currentSeqNum = currBlock.start;
244 ackFrame.ackBlocks.emplace_back(currBlock.start, currBlock.end);
245 }
246 return numAdditionalAckBlocks;
247 }
248
writeAckFrame(const quic::AckFrameMetaData & ackFrameMetaData,PacketBuilderInterface & builder)249 folly::Optional<AckFrameWriteResult> writeAckFrame(
250 const quic::AckFrameMetaData& ackFrameMetaData,
251 PacketBuilderInterface& builder) {
252 if (ackFrameMetaData.ackBlocks.empty()) {
253 return folly::none;
254 }
255 // The last block must be the largest block.
256 auto largestAckedPacket = ackFrameMetaData.ackBlocks.back().end;
257 // ackBlocks are already an interval set so each value is naturally
258 // non-overlapping.
259 auto firstAckBlockLength =
260 largestAckedPacket - ackFrameMetaData.ackBlocks.back().start;
261
262 WriteAckFrame ackFrame;
263 uint64_t spaceLeft = builder.remainingSpaceInPkt();
264 uint64_t beginningSpace = spaceLeft;
265 ackFrame.ackBlocks.reserve(spaceLeft / 4);
266
267 // We could technically split the range if the size of the representation of
268 // the integer is too large, but that gets super tricky and is of dubious
269 // value.
270 QuicInteger largestAckedPacketInt(largestAckedPacket);
271 QuicInteger firstAckBlockLengthInt(firstAckBlockLength);
272 // Convert ackDelay to unsigned value explicitly before right shifting to
273 // avoid issues with right shifting signed values.
274 uint64_t encodedAckDelay = ackFrameMetaData.ackDelay.count();
275 encodedAckDelay = encodedAckDelay >> ackFrameMetaData.ackDelayExponent;
276 QuicInteger ackDelayInt(encodedAckDelay);
277 QuicInteger minAdditionalAckBlockCount(0);
278
279 // Required fields are Type, LargestAcked, AckDelay, AckBlockCount,
280 // firstAckBlockLength
281 QuicInteger encodedintFrameType(static_cast<uint8_t>(FrameType::ACK));
282 auto headerSize = encodedintFrameType.getSize() +
283 largestAckedPacketInt.getSize() + ackDelayInt.getSize() +
284 minAdditionalAckBlockCount.getSize() + firstAckBlockLengthInt.getSize();
285 if (spaceLeft < headerSize) {
286 return folly::none;
287 }
288 spaceLeft -= headerSize;
289
290 ackFrame.ackBlocks.push_back(ackFrameMetaData.ackBlocks.back());
291 auto numAdditionalAckBlocks =
292 fillFrameWithAckBlocks(ackFrameMetaData.ackBlocks, ackFrame, spaceLeft);
293
294 QuicInteger numAdditionalAckBlocksInt(numAdditionalAckBlocks);
295 builder.write(encodedintFrameType);
296 builder.write(largestAckedPacketInt);
297 builder.write(ackDelayInt);
298 builder.write(numAdditionalAckBlocksInt);
299 builder.write(firstAckBlockLengthInt);
300
301 PacketNum currentSeqNum = ackFrameMetaData.ackBlocks.back().start;
302 for (auto it = ackFrame.ackBlocks.cbegin() + 1;
303 it != ackFrame.ackBlocks.cend();
304 ++it) {
305 CHECK_GE(currentSeqNum, it->end + 2);
306 PacketNum gap = currentSeqNum - it->end - 2;
307 PacketNum currBlockLen = it->end - it->start;
308 QuicInteger gapInt(gap);
309 QuicInteger currentBlockLenInt(currBlockLen);
310 builder.write(gapInt);
311 builder.write(currentBlockLenInt);
312 currentSeqNum = it->start;
313 }
314 ackFrame.ackDelay = ackFrameMetaData.ackDelay;
315 builder.appendFrame(std::move(ackFrame));
316 return AckFrameWriteResult(
317 beginningSpace - builder.remainingSpaceInPkt(),
318 1 + numAdditionalAckBlocks);
319 }
320
writeSimpleFrame(QuicSimpleFrame && frame,PacketBuilderInterface & builder)321 size_t writeSimpleFrame(
322 QuicSimpleFrame&& frame,
323 PacketBuilderInterface& builder) {
324 using FrameTypeType = std::underlying_type<FrameType>::type;
325
326 uint64_t spaceLeft = builder.remainingSpaceInPkt();
327
328 switch (frame.type()) {
329 case QuicSimpleFrame::Type::StopSendingFrame: {
330 const StopSendingFrame& stopSendingFrame = *frame.asStopSendingFrame();
331 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::STOP_SENDING));
332 QuicInteger streamId(stopSendingFrame.streamId);
333 QuicInteger errorCode(static_cast<uint64_t>(stopSendingFrame.errorCode));
334 size_t errorSize = errorCode.getSize();
335 auto stopSendingFrameSize =
336 intFrameType.getSize() + streamId.getSize() + errorSize;
337 if (packetSpaceCheck(spaceLeft, stopSendingFrameSize)) {
338 builder.write(intFrameType);
339 builder.write(streamId);
340 builder.write(errorCode);
341 builder.appendFrame(QuicSimpleFrame(std::move(stopSendingFrame)));
342 return stopSendingFrameSize;
343 }
344 // no space left in packet
345 return size_t(0);
346 }
347 case QuicSimpleFrame::Type::PathChallengeFrame: {
348 const PathChallengeFrame& pathChallengeFrame =
349 *frame.asPathChallengeFrame();
350 QuicInteger frameType(static_cast<uint8_t>(FrameType::PATH_CHALLENGE));
351 auto pathChallengeFrameSize =
352 frameType.getSize() + sizeof(pathChallengeFrame.pathData);
353 if (packetSpaceCheck(spaceLeft, pathChallengeFrameSize)) {
354 builder.write(frameType);
355 builder.writeBE(pathChallengeFrame.pathData);
356 builder.appendFrame(QuicSimpleFrame(std::move(pathChallengeFrame)));
357 return pathChallengeFrameSize;
358 }
359 // no space left in packet
360 return size_t(0);
361 }
362 case QuicSimpleFrame::Type::PathResponseFrame: {
363 const PathResponseFrame& pathResponseFrame = *frame.asPathResponseFrame();
364 QuicInteger frameType(static_cast<uint8_t>(FrameType::PATH_RESPONSE));
365 auto pathResponseFrameSize =
366 frameType.getSize() + sizeof(pathResponseFrame.pathData);
367 if (packetSpaceCheck(spaceLeft, pathResponseFrameSize)) {
368 builder.write(frameType);
369 builder.writeBE(pathResponseFrame.pathData);
370 builder.appendFrame(QuicSimpleFrame(std::move(pathResponseFrame)));
371 return pathResponseFrameSize;
372 }
373 // no space left in packet
374 return size_t(0);
375 }
376 case QuicSimpleFrame::Type::NewConnectionIdFrame: {
377 const NewConnectionIdFrame& newConnectionIdFrame =
378 *frame.asNewConnectionIdFrame();
379 QuicInteger frameType(static_cast<uint8_t>(FrameType::NEW_CONNECTION_ID));
380 QuicInteger sequenceNumber(newConnectionIdFrame.sequenceNumber);
381 QuicInteger retirePriorTo(newConnectionIdFrame.retirePriorTo);
382 // Include an 8-bit unsigned integer containing the length of the connId
383 auto newConnectionIdFrameSize = frameType.getSize() +
384 sequenceNumber.getSize() + retirePriorTo.getSize() + sizeof(uint8_t) +
385 newConnectionIdFrame.connectionId.size() +
386 newConnectionIdFrame.token.size();
387 if (packetSpaceCheck(spaceLeft, newConnectionIdFrameSize)) {
388 builder.write(frameType);
389 builder.write(sequenceNumber);
390 builder.write(retirePriorTo);
391 builder.writeBE(newConnectionIdFrame.connectionId.size());
392 builder.push(
393 newConnectionIdFrame.connectionId.data(),
394 newConnectionIdFrame.connectionId.size());
395 builder.push(
396 newConnectionIdFrame.token.data(),
397 newConnectionIdFrame.token.size());
398 builder.appendFrame(QuicSimpleFrame(std::move(newConnectionIdFrame)));
399 return newConnectionIdFrameSize;
400 }
401 // no space left in packet
402 return size_t(0);
403 }
404 case QuicSimpleFrame::Type::MaxStreamsFrame: {
405 const MaxStreamsFrame& maxStreamsFrame = *frame.asMaxStreamsFrame();
406 auto frameType = maxStreamsFrame.isForBidirectionalStream()
407 ? FrameType::MAX_STREAMS_BIDI
408 : FrameType::MAX_STREAMS_UNI;
409 QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
410 QuicInteger streamCount(maxStreamsFrame.maxStreams);
411 auto maxStreamsFrameSize = intFrameType.getSize() + streamCount.getSize();
412 if (packetSpaceCheck(spaceLeft, maxStreamsFrameSize)) {
413 builder.write(intFrameType);
414 builder.write(streamCount);
415 builder.appendFrame(QuicSimpleFrame(maxStreamsFrame));
416 return maxStreamsFrameSize;
417 }
418 return size_t(0);
419 }
420 case QuicSimpleFrame::Type::RetireConnectionIdFrame: {
421 const RetireConnectionIdFrame& retireConnectionIdFrame =
422 *frame.asRetireConnectionIdFrame();
423 QuicInteger frameType(
424 static_cast<uint8_t>(FrameType::RETIRE_CONNECTION_ID));
425 QuicInteger sequence(retireConnectionIdFrame.sequenceNumber);
426 auto retireConnectionIdFrameSize =
427 frameType.getSize() + sequence.getSize();
428 if (packetSpaceCheck(spaceLeft, retireConnectionIdFrameSize)) {
429 builder.write(frameType);
430 builder.write(sequence);
431 builder.appendFrame(QuicSimpleFrame(retireConnectionIdFrame));
432 return retireConnectionIdFrameSize;
433 }
434 // no space left in packet
435 return size_t(0);
436 }
437 case QuicSimpleFrame::Type::HandshakeDoneFrame: {
438 const HandshakeDoneFrame& handshakeDoneFrame =
439 *frame.asHandshakeDoneFrame();
440 CHECK(builder.getPacketHeader().asShort());
441 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::HANDSHAKE_DONE));
442 if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
443 builder.write(intFrameType);
444 builder.appendFrame(QuicSimpleFrame(handshakeDoneFrame));
445 return intFrameType.getSize();
446 }
447 // no space left in packet
448 return size_t(0);
449 }
450 case QuicSimpleFrame::Type::KnobFrame: {
451 const KnobFrame& knobFrame = *frame.asKnobFrame();
452 QuicInteger intFrameType(static_cast<uint64_t>(FrameType::KNOB));
453 QuicInteger intKnobSpace(knobFrame.knobSpace);
454 QuicInteger intKnobId(knobFrame.id);
455 QuicInteger intKnobLen(knobFrame.len);
456 size_t knobFrameLen = intFrameType.getSize() + intKnobSpace.getSize() +
457 intKnobId.getSize() + intKnobLen.getSize() + intKnobLen.getValue();
458 if (packetSpaceCheck(spaceLeft, knobFrameLen)) {
459 builder.write(intFrameType);
460 builder.write(intKnobSpace);
461 builder.write(intKnobId);
462 builder.write(intKnobLen);
463 builder.insert(knobFrame.blob->clone());
464 builder.appendFrame(QuicSimpleFrame(knobFrame));
465 return knobFrameLen;
466 }
467 // no space left in packet
468 return size_t(0);
469 }
470 case QuicSimpleFrame::Type::AckFrequencyFrame: {
471 const auto ackFrequencyFrame = frame.asAckFrequencyFrame();
472 QuicInteger intFrameType(static_cast<uint64_t>(FrameType::ACK_FREQUENCY));
473 QuicInteger intSequenceNumber(ackFrequencyFrame->sequenceNumber);
474 QuicInteger intPacketTolerance(ackFrequencyFrame->packetTolerance);
475 QuicInteger intUpdateMaxAckDelay(ackFrequencyFrame->updateMaxAckDelay);
476 size_t ackFrequencyFrameLen = intFrameType.getSize() +
477 intSequenceNumber.getSize() + intPacketTolerance.getSize() +
478 intUpdateMaxAckDelay.getSize() + 1 /* ignoreOrder */;
479 if (packetSpaceCheck(spaceLeft, ackFrequencyFrameLen)) {
480 builder.write(intFrameType);
481 builder.write(intSequenceNumber);
482 builder.write(intPacketTolerance);
483 builder.write(intUpdateMaxAckDelay);
484 builder.writeBE(ackFrequencyFrame->ignoreOrder);
485 builder.appendFrame(QuicSimpleFrame(*ackFrequencyFrame));
486 return ackFrequencyFrameLen;
487 }
488 // no space left in packet
489 return size_t(0);
490 }
491 }
492 folly::assume_unreachable();
493 }
494
writeFrame(QuicWriteFrame && frame,PacketBuilderInterface & builder)495 size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
496 using FrameTypeType = std::underlying_type<FrameType>::type;
497
498 uint64_t spaceLeft = builder.remainingSpaceInPkt();
499
500 switch (frame.type()) {
501 case QuicWriteFrame::Type::PaddingFrame: {
502 PaddingFrame& paddingFrame = *frame.asPaddingFrame();
503 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PADDING));
504 if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
505 builder.write(intFrameType);
506 builder.appendFrame(std::move(paddingFrame));
507 return intFrameType.getSize();
508 }
509 return size_t(0);
510 }
511 case QuicWriteFrame::Type::RstStreamFrame: {
512 RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
513 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::RST_STREAM));
514 QuicInteger streamId(rstStreamFrame.streamId);
515 QuicInteger offset(rstStreamFrame.offset);
516 QuicInteger errorCode(static_cast<uint64_t>(rstStreamFrame.errorCode));
517 size_t errorSize = errorCode.getSize();
518 auto rstStreamFrameSize = intFrameType.getSize() + errorSize +
519 streamId.getSize() + offset.getSize();
520 if (packetSpaceCheck(spaceLeft, rstStreamFrameSize)) {
521 builder.write(intFrameType);
522 builder.write(streamId);
523 builder.write(errorCode);
524 builder.write(offset);
525 builder.appendFrame(std::move(rstStreamFrame));
526 return rstStreamFrameSize;
527 }
528 // no space left in packet
529 return size_t(0);
530 }
531 case QuicWriteFrame::Type::MaxDataFrame: {
532 MaxDataFrame& maxDataFrame = *frame.asMaxDataFrame();
533 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::MAX_DATA));
534 QuicInteger maximumData(maxDataFrame.maximumData);
535 auto frameSize = intFrameType.getSize() + maximumData.getSize();
536 if (packetSpaceCheck(spaceLeft, frameSize)) {
537 builder.write(intFrameType);
538 builder.write(maximumData);
539 builder.appendFrame(std::move(maxDataFrame));
540 return frameSize;
541 }
542 // no space left in packet
543 return size_t(0);
544 }
545 case QuicWriteFrame::Type::MaxStreamDataFrame: {
546 MaxStreamDataFrame& maxStreamDataFrame = *frame.asMaxStreamDataFrame();
547 QuicInteger intFrameType(
548 static_cast<uint8_t>(FrameType::MAX_STREAM_DATA));
549 QuicInteger streamId(maxStreamDataFrame.streamId);
550 QuicInteger maximumData(maxStreamDataFrame.maximumData);
551 auto maxStreamDataFrameSize =
552 intFrameType.getSize() + streamId.getSize() + maximumData.getSize();
553 if (packetSpaceCheck(spaceLeft, maxStreamDataFrameSize)) {
554 builder.write(intFrameType);
555 builder.write(streamId);
556 builder.write(maximumData);
557 builder.appendFrame(std::move(maxStreamDataFrame));
558 return maxStreamDataFrameSize;
559 }
560 // no space left in packet
561 return size_t(0);
562 }
563 case QuicWriteFrame::Type::DataBlockedFrame: {
564 DataBlockedFrame& blockedFrame = *frame.asDataBlockedFrame();
565 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::DATA_BLOCKED));
566 QuicInteger dataLimit(blockedFrame.dataLimit);
567 auto blockedFrameSize = intFrameType.getSize() + dataLimit.getSize();
568 if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
569 builder.write(intFrameType);
570 builder.write(dataLimit);
571 builder.appendFrame(std::move(blockedFrame));
572 return blockedFrameSize;
573 }
574 // no space left in packet
575 return size_t(0);
576 }
577 case QuicWriteFrame::Type::StreamDataBlockedFrame: {
578 StreamDataBlockedFrame& streamBlockedFrame =
579 *frame.asStreamDataBlockedFrame();
580 QuicInteger intFrameType(
581 static_cast<uint8_t>(FrameType::STREAM_DATA_BLOCKED));
582 QuicInteger streamId(streamBlockedFrame.streamId);
583 QuicInteger dataLimit(streamBlockedFrame.dataLimit);
584 auto blockedFrameSize =
585 intFrameType.getSize() + streamId.getSize() + dataLimit.getSize();
586 if (packetSpaceCheck(spaceLeft, blockedFrameSize)) {
587 builder.write(intFrameType);
588 builder.write(streamId);
589 builder.write(dataLimit);
590 builder.appendFrame(std::move(streamBlockedFrame));
591 return blockedFrameSize;
592 }
593 // no space left in packet
594 return size_t(0);
595 }
596 case QuicWriteFrame::Type::StreamsBlockedFrame: {
597 StreamsBlockedFrame& streamsBlockedFrame = *frame.asStreamsBlockedFrame();
598 auto frameType = streamsBlockedFrame.isForBidirectionalStream()
599 ? FrameType::STREAMS_BLOCKED_BIDI
600 : FrameType::STREAMS_BLOCKED_UNI;
601 QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
602 QuicInteger streamId(streamsBlockedFrame.streamLimit);
603 auto streamBlockedFrameSize = intFrameType.getSize() + streamId.getSize();
604 if (packetSpaceCheck(spaceLeft, streamBlockedFrameSize)) {
605 builder.write(intFrameType);
606 builder.write(streamId);
607 builder.appendFrame(std::move(streamsBlockedFrame));
608 return streamBlockedFrameSize;
609 }
610 // no space left in packet
611 return size_t(0);
612 }
613 case QuicWriteFrame::Type::ConnectionCloseFrame: {
614 ConnectionCloseFrame& connectionCloseFrame =
615 *frame.asConnectionCloseFrame();
616 // Need to distinguish between CONNECTION_CLOSE & CONNECTINO_CLOSE_APP_ERR
617 const TransportErrorCode* isTransportErrorCode =
618 connectionCloseFrame.errorCode.asTransportErrorCode();
619 const ApplicationErrorCode* isApplicationErrorCode =
620 connectionCloseFrame.errorCode.asApplicationErrorCode();
621
622 QuicInteger intFrameType(static_cast<uint8_t>(
623 isTransportErrorCode ? FrameType::CONNECTION_CLOSE
624 : FrameType::CONNECTION_CLOSE_APP_ERR));
625
626 QuicInteger reasonLength(connectionCloseFrame.reasonPhrase.size());
627 folly::Optional<QuicInteger> closingFrameType;
628 if (isTransportErrorCode) {
629 closingFrameType = QuicInteger(
630 static_cast<FrameTypeType>(connectionCloseFrame.closingFrameType));
631 }
632
633 QuicInteger errorCode(
634 isTransportErrorCode
635 ? static_cast<uint64_t>(TransportErrorCode(*isTransportErrorCode))
636 : static_cast<uint64_t>(
637 ApplicationErrorCode(*isApplicationErrorCode)));
638 size_t errorSize = errorCode.getSize();
639 auto connCloseFrameSize = intFrameType.getSize() + errorSize +
640 (closingFrameType ? closingFrameType.value().getSize() : 0) +
641 reasonLength.getSize() + connectionCloseFrame.reasonPhrase.size();
642 if (packetSpaceCheck(spaceLeft, connCloseFrameSize)) {
643 builder.write(intFrameType);
644 builder.write(errorCode);
645 if (closingFrameType) {
646 builder.write(closingFrameType.value());
647 }
648 builder.write(reasonLength);
649 builder.push(
650 (const uint8_t*)connectionCloseFrame.reasonPhrase.data(),
651 connectionCloseFrame.reasonPhrase.size());
652 builder.appendFrame(std::move(connectionCloseFrame));
653 return connCloseFrameSize;
654 }
655 // no space left in packet
656 return size_t(0);
657 }
658 case QuicWriteFrame::Type::PingFrame: {
659 const PingFrame& pingFrame = *frame.asPingFrame();
660 QuicInteger intFrameType(static_cast<uint8_t>(FrameType::PING));
661 if (packetSpaceCheck(spaceLeft, intFrameType.getSize())) {
662 builder.write(intFrameType);
663 builder.appendFrame(pingFrame);
664 return intFrameType.getSize();
665 }
666 // no space left in packet
667 return size_t(0);
668 }
669 case QuicWriteFrame::Type::QuicSimpleFrame: {
670 return writeSimpleFrame(std::move(*frame.asQuicSimpleFrame()), builder);
671 }
672 case QuicWriteFrame::Type::DatagramFrame: {
673 const DatagramFrame& datagramFrame = *frame.asDatagramFrame();
674 QuicInteger frameTypeQuicInt(
675 static_cast<uint8_t>(FrameType::DATAGRAM_LEN));
676 QuicInteger datagramLenInt(datagramFrame.length);
677 auto datagramFrameLength = frameTypeQuicInt.getSize() +
678 datagramFrame.length + datagramLenInt.getSize();
679 if (packetSpaceCheck(spaceLeft, datagramFrameLength)) {
680 builder.write(frameTypeQuicInt);
681 builder.write(datagramLenInt);
682 builder.insert(std::move(datagramFrame.data), datagramFrame.length);
683 builder.appendFrame(datagramFrame);
684 return datagramFrameLength;
685 }
686 // no space left in packet
687 return size_t(0);
688 }
689 default: {
690 // TODO add support for: RETIRE_CONNECTION_ID and NEW_TOKEN frames
691 auto errorStr = folly::to<std::string>(
692 "Unknown / unsupported frame type received at ", __func__);
693 VLOG(2) << errorStr;
694 throw QuicTransportException(
695 errorStr, TransportErrorCode::FRAME_ENCODING_ERROR);
696 }
697 }
698 }
699 } // namespace quic
700