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/QuicConstants.h>
10 #include <quic/QuicException.h>
11 #include <quic/api/QuicTransportFunctions.h>
12 #include <quic/client/state/ClientStateMachine.h>
13 #include <quic/codec/QuicPacketBuilder.h>
14 #include <quic/codec/QuicWriteCodec.h>
15 #include <quic/codec/Types.h>
16 #include <quic/flowcontrol/QuicFlowController.h>
17 #include <quic/happyeyeballs/QuicHappyEyeballsFunctions.h>
18
19 #include <quic/state/AckHandlers.h>
20 #include <quic/state/QuicStateFunctions.h>
21 #include <quic/state/QuicStreamFunctions.h>
22 #include <quic/state/SimpleFrameFunctions.h>
23
24 namespace {
25
26 /*
27 * Check whether crypto has pending data.
28 */
cryptoHasWritableData(const quic::QuicConnectionStateBase & conn)29 bool cryptoHasWritableData(const quic::QuicConnectionStateBase& conn) {
30 return (conn.initialWriteCipher &&
31 (!conn.cryptoState->initialStream.writeBuffer.empty() ||
32 !conn.cryptoState->initialStream.lossBuffer.empty())) ||
33 (conn.handshakeWriteCipher &&
34 (!conn.cryptoState->handshakeStream.writeBuffer.empty() ||
35 !conn.cryptoState->handshakeStream.lossBuffer.empty())) ||
36 (conn.oneRttWriteCipher &&
37 (!conn.cryptoState->oneRttStream.writeBuffer.empty() ||
38 !conn.cryptoState->oneRttStream.lossBuffer.empty()));
39 }
40
optionalToString(const folly::Optional<quic::PacketNum> & packetNum)41 std::string optionalToString(
42 const folly::Optional<quic::PacketNum>& packetNum) {
43 if (!packetNum) {
44 return "-";
45 }
46 return folly::to<std::string>(*packetNum);
47 }
48
largestAckScheduledToString(const quic::QuicConnectionStateBase & conn)49 std::string largestAckScheduledToString(
50 const quic::QuicConnectionStateBase& conn) noexcept {
51 return folly::to<std::string>(
52 "[",
53 optionalToString(conn.ackStates.initialAckState.largestAckScheduled),
54 ",",
55 optionalToString(conn.ackStates.handshakeAckState.largestAckScheduled),
56 ",",
57 optionalToString(conn.ackStates.appDataAckState.largestAckScheduled),
58 "]");
59 }
60
largestAckToSendToString(const quic::QuicConnectionStateBase & conn)61 std::string largestAckToSendToString(
62 const quic::QuicConnectionStateBase& conn) noexcept {
63 return folly::to<std::string>(
64 "[",
65 optionalToString(largestAckToSend(conn.ackStates.initialAckState)),
66 ",",
67 optionalToString(largestAckToSend(conn.ackStates.handshakeAckState)),
68 ",",
69 optionalToString(largestAckToSend(conn.ackStates.appDataAckState)),
70 "]");
71 }
72
toWriteInitialAcks(const quic::QuicConnectionStateBase & conn)73 bool toWriteInitialAcks(const quic::QuicConnectionStateBase& conn) {
74 return (
75 conn.initialWriteCipher &&
76 hasAcksToSchedule(conn.ackStates.initialAckState) &&
77 conn.ackStates.initialAckState.needsToSendAckImmediately);
78 }
79
toWriteHandshakeAcks(const quic::QuicConnectionStateBase & conn)80 bool toWriteHandshakeAcks(const quic::QuicConnectionStateBase& conn) {
81 return (
82 conn.handshakeWriteCipher &&
83 hasAcksToSchedule(conn.ackStates.handshakeAckState) &&
84 conn.ackStates.handshakeAckState.needsToSendAckImmediately);
85 }
86
toWriteAppDataAcks(const quic::QuicConnectionStateBase & conn)87 bool toWriteAppDataAcks(const quic::QuicConnectionStateBase& conn) {
88 return (
89 conn.oneRttWriteCipher &&
90 hasAcksToSchedule(conn.ackStates.appDataAckState) &&
91 conn.ackStates.appDataAckState.needsToSendAckImmediately);
92 }
93
94 using namespace quic;
95
writeQuicDataToSocketImpl(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,uint64_t packetLimit,bool exceptCryptoStream)96 WriteQuicDataResult writeQuicDataToSocketImpl(
97 folly::AsyncUDPSocket& sock,
98 QuicConnectionStateBase& connection,
99 const ConnectionId& srcConnId,
100 const ConnectionId& dstConnId,
101 const Aead& aead,
102 const PacketNumberCipher& headerCipher,
103 QuicVersion version,
104 uint64_t packetLimit,
105 bool exceptCryptoStream) {
106 auto builder = ShortHeaderBuilder();
107 WriteQuicDataResult result;
108 auto& packetsWritten = result.packetsWritten;
109 auto& probesWritten = result.probesWritten;
110 auto& numProbePackets =
111 connection.pendingEvents.numProbePackets[PacketNumberSpace::AppData];
112 if (numProbePackets) {
113 auto probeSchedulerBuilder =
114 FrameScheduler::Builder(
115 connection,
116 EncryptionLevel::AppData,
117 PacketNumberSpace::AppData,
118 exceptCryptoStream ? "ProbeWithoutCrypto" : "ProbeScheduler")
119 .blockedFrames()
120 .windowUpdateFrames()
121 .simpleFrames()
122 .resetFrames()
123 .streamFrames()
124 .pingFrames();
125 if (!exceptCryptoStream) {
126 probeSchedulerBuilder.cryptoFrames();
127 }
128 auto probeScheduler = std::move(probeSchedulerBuilder).build();
129 probesWritten = writeProbingDataToSocket(
130 sock,
131 connection,
132 srcConnId,
133 dstConnId,
134 builder,
135 EncryptionLevel::AppData,
136 PacketNumberSpace::AppData,
137 probeScheduler,
138 numProbePackets, // This possibly bypasses the packetLimit.
139 aead,
140 headerCipher,
141 version);
142 // We only get one chance to write out the probes.
143 numProbePackets = 0;
144 packetLimit =
145 probesWritten > packetLimit ? 0 : (packetLimit - probesWritten);
146 }
147 auto schedulerBuilder =
148 FrameScheduler::Builder(
149 connection,
150 EncryptionLevel::AppData,
151 PacketNumberSpace::AppData,
152 exceptCryptoStream ? "FrameSchedulerWithoutCrypto" : "FrameScheduler")
153 .streamFrames()
154 .ackFrames()
155 .resetFrames()
156 .windowUpdateFrames()
157 .blockedFrames()
158 .simpleFrames()
159 .pingFrames()
160 .datagramFrames();
161 if (!exceptCryptoStream) {
162 schedulerBuilder.cryptoFrames();
163 }
164 FrameScheduler scheduler = std::move(schedulerBuilder).build();
165 packetsWritten = writeConnectionDataToSocket(
166 sock,
167 connection,
168 srcConnId,
169 dstConnId,
170 std::move(builder),
171 PacketNumberSpace::AppData,
172 scheduler,
173 congestionControlWritableBytes,
174 packetLimit,
175 aead,
176 headerCipher,
177 version);
178 VLOG_IF(10, packetsWritten || probesWritten)
179 << nodeToString(connection.nodeType) << " written data "
180 << (exceptCryptoStream ? "without crypto data " : "")
181 << "to socket packets=" << packetsWritten << " probes=" << probesWritten
182 << " " << connection;
183 return result;
184 }
185
continuousMemoryBuildScheduleEncrypt(QuicConnectionStateBase & connection,PacketHeader header,PacketNumberSpace pnSpace,PacketNum packetNum,uint64_t cipherOverhead,QuicPacketScheduler & scheduler,uint64_t writableBytes,IOBufQuicBatch & ioBufBatch,const Aead & aead,const PacketNumberCipher & headerCipher)186 DataPathResult continuousMemoryBuildScheduleEncrypt(
187 QuicConnectionStateBase& connection,
188 PacketHeader header,
189 PacketNumberSpace pnSpace,
190 PacketNum packetNum,
191 uint64_t cipherOverhead,
192 QuicPacketScheduler& scheduler,
193 uint64_t writableBytes,
194 IOBufQuicBatch& ioBufBatch,
195 const Aead& aead,
196 const PacketNumberCipher& headerCipher) {
197 auto buf = connection.bufAccessor->obtain();
198 auto prevSize = buf->length();
199 connection.bufAccessor->release(std::move(buf));
200
201 auto rollbackBuf = [&]() {
202 auto buf = connection.bufAccessor->obtain();
203 buf->trimEnd(buf->length() - prevSize);
204 connection.bufAccessor->release(std::move(buf));
205 };
206
207 // It's the scheduler's job to invoke encode header
208 InplaceQuicPacketBuilder pktBuilder(
209 *connection.bufAccessor,
210 connection.udpSendPacketLen,
211 std::move(header),
212 getAckState(connection, pnSpace).largestAckedByPeer.value_or(0));
213 pktBuilder.accountForCipherOverhead(cipherOverhead);
214 CHECK(scheduler.hasData());
215 auto result =
216 scheduler.scheduleFramesForPacket(std::move(pktBuilder), writableBytes);
217 CHECK(connection.bufAccessor->ownsBuffer());
218 auto& packet = result.packet;
219 if (!packet || packet->packet.frames.empty()) {
220 rollbackBuf();
221 ioBufBatch.flush();
222 if (connection.loopDetectorCallback) {
223 connection.writeDebugState.noWriteReason = NoWriteReason::NO_FRAME;
224 }
225 return DataPathResult::makeBuildFailure();
226 }
227 if (!packet->body) {
228 // No more space remaining.
229 rollbackBuf();
230 ioBufBatch.flush();
231 if (connection.loopDetectorCallback) {
232 connection.writeDebugState.noWriteReason = NoWriteReason::NO_BODY;
233 }
234 return DataPathResult::makeBuildFailure();
235 }
236 CHECK(!packet->header->isChained());
237 auto headerLen = packet->header->length();
238 buf = connection.bufAccessor->obtain();
239 CHECK(
240 packet->body->data() > buf->data() &&
241 packet->body->tail() <= buf->tail());
242 CHECK(
243 packet->header->data() >= buf->data() &&
244 packet->header->tail() < buf->tail());
245 // Trim off everything before the current packet, and the header length, so
246 // buf's data starts from the body part of buf.
247 buf->trimStart(prevSize + headerLen);
248 // buf and packetBuf is actually the same.
249 auto packetBuf =
250 aead.inplaceEncrypt(std::move(buf), packet->header.get(), packetNum);
251 CHECK(packetBuf->headroom() == headerLen + prevSize);
252 // Include header back.
253 packetBuf->prepend(headerLen);
254
255 HeaderForm headerForm = packet->packet.header.getHeaderForm();
256 encryptPacketHeader(
257 headerForm,
258 packetBuf->writableData(),
259 headerLen,
260 packetBuf->data() + headerLen,
261 packetBuf->length() - headerLen,
262 headerCipher);
263 CHECK(!packetBuf->isChained());
264 auto encodedSize = packetBuf->length();
265 auto encodedBodySize = encodedSize - headerLen;
266 // Include previous packets back.
267 packetBuf->prepend(prevSize);
268 connection.bufAccessor->release(std::move(packetBuf));
269 #if !FOLLY_MOBILE
270 bool isD6DProbe = pnSpace == PacketNumberSpace::AppData &&
271 connection.d6d.lastProbe.hasValue() &&
272 connection.d6d.lastProbe->packetNum == packetNum;
273 if (!isD6DProbe && encodedSize > connection.udpSendPacketLen) {
274 LOG_EVERY_N(ERROR, 5000)
275 << "Quic sending pkt larger than limit, encodedSize=" << encodedSize;
276 }
277 #endif
278 // TODO: I think we should add an API that doesn't need a buffer.
279 bool ret = ioBufBatch.write(nullptr /* no need to pass buf */, encodedSize);
280 // update stats and connection
281 if (ret) {
282 QUIC_STATS(connection.statsCallback, onWrite, encodedSize);
283 QUIC_STATS(connection.statsCallback, onPacketSent);
284 }
285 return DataPathResult::makeWriteResult(
286 ret, std::move(result), encodedSize, encodedBodySize);
287 }
288
iobufChainBasedBuildScheduleEncrypt(QuicConnectionStateBase & connection,PacketHeader header,PacketNumberSpace pnSpace,PacketNum packetNum,uint64_t cipherOverhead,QuicPacketScheduler & scheduler,uint64_t writableBytes,IOBufQuicBatch & ioBufBatch,const Aead & aead,const PacketNumberCipher & headerCipher)289 DataPathResult iobufChainBasedBuildScheduleEncrypt(
290 QuicConnectionStateBase& connection,
291 PacketHeader header,
292 PacketNumberSpace pnSpace,
293 PacketNum packetNum,
294 uint64_t cipherOverhead,
295 QuicPacketScheduler& scheduler,
296 uint64_t writableBytes,
297 IOBufQuicBatch& ioBufBatch,
298 const Aead& aead,
299 const PacketNumberCipher& headerCipher) {
300 RegularQuicPacketBuilder pktBuilder(
301 connection.udpSendPacketLen,
302 std::move(header),
303 getAckState(connection, pnSpace).largestAckedByPeer.value_or(0));
304 // It's the scheduler's job to invoke encode header
305 pktBuilder.accountForCipherOverhead(cipherOverhead);
306 auto result =
307 scheduler.scheduleFramesForPacket(std::move(pktBuilder), writableBytes);
308 auto& packet = result.packet;
309 if (!packet || packet->packet.frames.empty()) {
310 ioBufBatch.flush();
311 if (connection.loopDetectorCallback) {
312 connection.writeDebugState.noWriteReason = NoWriteReason::NO_FRAME;
313 }
314 return DataPathResult::makeBuildFailure();
315 }
316 if (!packet->body) {
317 // No more space remaining.
318 ioBufBatch.flush();
319 if (connection.loopDetectorCallback) {
320 connection.writeDebugState.noWriteReason = NoWriteReason::NO_BODY;
321 }
322 return DataPathResult::makeBuildFailure();
323 }
324 packet->header->coalesce();
325 auto headerLen = packet->header->length();
326 auto bodyLen = packet->body->computeChainDataLength();
327 auto unencrypted =
328 folly::IOBuf::create(headerLen + bodyLen + aead.getCipherOverhead());
329 auto bodyCursor = folly::io::Cursor(packet->body.get());
330 bodyCursor.pull(unencrypted->writableData() + headerLen, bodyLen);
331 unencrypted->advance(headerLen);
332 unencrypted->append(bodyLen);
333 auto packetBuf = aead.inplaceEncrypt(
334 std::move(unencrypted), packet->header.get(), packetNum);
335 DCHECK(packetBuf->headroom() == headerLen);
336 packetBuf->clear();
337 auto headerCursor = folly::io::Cursor(packet->header.get());
338 headerCursor.pull(packetBuf->writableData(), headerLen);
339 packetBuf->append(headerLen + bodyLen + aead.getCipherOverhead());
340
341 HeaderForm headerForm = packet->packet.header.getHeaderForm();
342 encryptPacketHeader(
343 headerForm,
344 packetBuf->writableData(),
345 headerLen,
346 packetBuf->data() + headerLen,
347 packetBuf->length() - headerLen,
348 headerCipher);
349 auto encodedSize = packetBuf->computeChainDataLength();
350 auto encodedBodySize = encodedSize - headerLen;
351 #if !FOLLY_MOBILE
352 if (encodedSize > connection.udpSendPacketLen) {
353 LOG_EVERY_N(ERROR, 5000)
354 << "Quic sending pkt larger than limit, encodedSize=" << encodedSize
355 << " encodedBodySize=" << encodedBodySize;
356 }
357 #endif
358 bool ret = ioBufBatch.write(std::move(packetBuf), encodedSize);
359 if (ret) {
360 // update stats and connection
361 QUIC_STATS(connection.statsCallback, onWrite, encodedSize);
362 QUIC_STATS(connection.statsCallback, onPacketSent);
363 }
364 return DataPathResult::makeWriteResult(
365 ret, std::move(result), encodedSize, encodedBodySize);
366 }
367
368 } // namespace
369
370 namespace quic {
371
372 void handleNewStreamBufMetaWritten(
373 QuicStreamState& stream,
374 uint64_t frameLen,
375 bool frameFin);
376
377 void handleRetransmissionBufMetaWritten(
378 QuicStreamState& stream,
379 uint64_t frameOffset,
380 uint64_t frameLen,
381 bool frameFin,
382 const decltype(stream.lossBufMetas)::iterator lossBufMetaIter);
383
writeLoopTimeLimit(TimePoint loopBeginTime,const QuicConnectionStateBase & connection)384 bool writeLoopTimeLimit(
385 TimePoint loopBeginTime,
386 const QuicConnectionStateBase& connection) {
387 return connection.lossState.srtt == 0us ||
388 Clock::now() - loopBeginTime < connection.lossState.srtt /
389 connection.transportSettings.writeLimitRttFraction;
390 }
391
handleNewStreamDataWritten(QuicStreamLike & stream,uint64_t frameLen,bool frameFin)392 void handleNewStreamDataWritten(
393 QuicStreamLike& stream,
394 uint64_t frameLen,
395 bool frameFin) {
396 auto originalOffset = stream.currentWriteOffset;
397 // Idealy we should also check this data doesn't exist in either retx buffer
398 // or loss buffer, but that's an expensive search.
399 stream.currentWriteOffset += frameLen;
400 auto bufWritten = stream.writeBuffer.splitAtMost(folly::to<size_t>(frameLen));
401 DCHECK_EQ(bufWritten->computeChainDataLength(), frameLen);
402 // TODO: If we want to be able to write FIN out of order for DSR-ed streams,
403 // this needs to be fixed:
404 stream.currentWriteOffset += frameFin ? 1 : 0;
405 CHECK(stream.retransmissionBuffer
406 .emplace(
407 std::piecewise_construct,
408 std::forward_as_tuple(originalOffset),
409 std::forward_as_tuple(std::make_unique<StreamBuffer>(
410 std::move(bufWritten), originalOffset, frameFin)))
411 .second);
412 }
413
handleNewStreamBufMetaWritten(QuicStreamState & stream,uint64_t frameLen,bool frameFin)414 void handleNewStreamBufMetaWritten(
415 QuicStreamState& stream,
416 uint64_t frameLen,
417 bool frameFin) {
418 CHECK_GT(stream.writeBufMeta.offset, 0);
419 auto originalOffset = stream.writeBufMeta.offset;
420 auto bufMetaSplit = stream.writeBufMeta.split(frameLen);
421 CHECK_EQ(bufMetaSplit.offset, originalOffset);
422 if (frameFin) {
423 // If FIN is written, nothing should be left in the writeBufMeta.
424 CHECK_EQ(0, stream.writeBufMeta.length);
425 ++stream.writeBufMeta.offset;
426 CHECK_GT(stream.writeBufMeta.offset, *stream.finalWriteOffset);
427 }
428 CHECK(stream.retransmissionBufMetas
429 .emplace(
430 std::piecewise_construct,
431 std::forward_as_tuple(originalOffset),
432 std::forward_as_tuple(bufMetaSplit))
433 .second);
434 }
435
handleRetransmissionWritten(QuicStreamLike & stream,uint64_t frameOffset,uint64_t frameLen,bool frameFin,std::deque<StreamBuffer>::iterator lossBufferIter)436 void handleRetransmissionWritten(
437 QuicStreamLike& stream,
438 uint64_t frameOffset,
439 uint64_t frameLen,
440 bool frameFin,
441 std::deque<StreamBuffer>::iterator lossBufferIter) {
442 auto bufferLen = lossBufferIter->data.chainLength();
443 Buf bufWritten;
444 if (frameLen == bufferLen && frameFin == lossBufferIter->eof) {
445 // The buffer is entirely retransmitted
446 bufWritten = lossBufferIter->data.move();
447 stream.lossBuffer.erase(lossBufferIter);
448 } else {
449 lossBufferIter->offset += frameLen;
450 bufWritten = lossBufferIter->data.splitAtMost(frameLen);
451 }
452 CHECK(stream.retransmissionBuffer
453 .emplace(
454 std::piecewise_construct,
455 std::forward_as_tuple(frameOffset),
456 std::forward_as_tuple(std::make_unique<StreamBuffer>(
457 std::move(bufWritten), frameOffset, frameFin)))
458 .second);
459 }
460
461 void handleRetransmissionBufMetaWritten(
462 QuicStreamState& stream,
463 uint64_t frameOffset,
464 uint64_t frameLen,
465 bool frameFin,
466 const decltype(stream.lossBufMetas)::iterator lossBufMetaIter) {
467 if (frameLen == lossBufMetaIter->length && frameFin == lossBufMetaIter->eof) {
468 stream.lossBufMetas.erase(lossBufMetaIter);
469 } else {
470 CHECK_GT(lossBufMetaIter->length, frameLen);
471 lossBufMetaIter->length -= frameLen;
472 lossBufMetaIter->offset += frameLen;
473 }
474 CHECK(stream.retransmissionBufMetas
475 .emplace(
476 std::piecewise_construct,
477 std::forward_as_tuple(frameOffset),
478 std::forward_as_tuple(WriteBufferMeta::Builder()
479 .setOffset(frameOffset)
480 .setLength(frameLen)
481 .setEOF(frameFin)
482 .build()))
483 .second);
484 }
485
486 /**
487 * Update the connection and stream state after stream data is written and deal
488 * with new data, as well as retranmissions. Returns true if the data sent is
489 * new data.
490 */
handleStreamWritten(QuicConnectionStateBase & conn,QuicStreamLike & stream,uint64_t frameOffset,uint64_t frameLen,bool frameFin,PacketNum packetNum,PacketNumberSpace packetNumberSpace)491 bool handleStreamWritten(
492 QuicConnectionStateBase& conn,
493 QuicStreamLike& stream,
494 uint64_t frameOffset,
495 uint64_t frameLen,
496 bool frameFin,
497 PacketNum packetNum,
498 PacketNumberSpace packetNumberSpace) {
499 auto writtenNewData = false;
500 // Handle new data first
501 if (frameOffset == stream.currentWriteOffset) {
502 handleNewStreamDataWritten(stream, frameLen, frameFin);
503 writtenNewData = true;
504 }
505
506 if (writtenNewData) {
507 // Count packet. It's based on the assumption that schedluing scheme will
508 // only writes one STREAM frame for a stream in a packet. If that doesn't
509 // hold, we need to avoid double-counting.
510 ++stream.numPacketsTxWithNewData;
511 VLOG(10) << nodeToString(conn.nodeType) << " sent"
512 << " packetNum=" << packetNum << " space=" << packetNumberSpace
513 << " " << conn;
514 return true;
515 }
516
517 bool writtenRetx = false;
518 // If the data is in the loss buffer, it is a retransmission.
519 auto lossBufferIter = std::lower_bound(
520 stream.lossBuffer.begin(),
521 stream.lossBuffer.end(),
522 frameOffset,
523 [](const auto& buf, auto off) { return buf.offset < off; });
524 if (lossBufferIter != stream.lossBuffer.end() &&
525 lossBufferIter->offset == frameOffset) {
526 handleRetransmissionWritten(
527 stream, frameOffset, frameLen, frameFin, lossBufferIter);
528 writtenRetx = true;
529 }
530
531 if (writtenRetx) {
532 conn.lossState.totalBytesRetransmitted += frameLen;
533 VLOG(10) << nodeToString(conn.nodeType) << " sent retransmission"
534 << " packetNum=" << packetNum << " " << conn;
535 QUIC_STATS(conn.statsCallback, onPacketRetransmission);
536 return false;
537 }
538
539 // Otherwise it must be a clone write.
540 conn.lossState.totalStreamBytesCloned += frameLen;
541 return false;
542 }
543
handleStreamBufMetaWritten(QuicConnectionStateBase & conn,QuicStreamState & stream,uint64_t frameOffset,uint64_t frameLen,bool frameFin,PacketNum packetNum,PacketNumberSpace packetNumberSpace)544 bool handleStreamBufMetaWritten(
545 QuicConnectionStateBase& conn,
546 QuicStreamState& stream,
547 uint64_t frameOffset,
548 uint64_t frameLen,
549 bool frameFin,
550 PacketNum packetNum,
551 PacketNumberSpace packetNumberSpace) {
552 auto writtenNewData = false;
553 // Handle new data first
554 if (stream.writeBufMeta.offset > 0 &&
555 frameOffset == stream.writeBufMeta.offset) {
556 handleNewStreamBufMetaWritten(stream, frameLen, frameFin);
557 writtenNewData = true;
558 }
559
560 if (writtenNewData) {
561 // Count packet. It's based on the assumption that schedluing scheme will
562 // only writes one STREAM frame for a stream in a packet. If that doesn't
563 // hold, we need to avoid double-counting.
564 ++stream.numPacketsTxWithNewData;
565 VLOG(10) << nodeToString(conn.nodeType) << " sent"
566 << " packetNum=" << packetNum << " space=" << packetNumberSpace
567 << " " << conn;
568 return true;
569 }
570
571 auto lossBufMetaIter = std::lower_bound(
572 stream.lossBufMetas.begin(),
573 stream.lossBufMetas.end(),
574 frameOffset,
575 [](const auto& bufMeta, auto offset) { return bufMeta.offset < offset; });
576 // We do not clone BufMeta right now. So the data has to be in lossBufMetas.
577 CHECK(lossBufMetaIter != stream.lossBufMetas.end());
578 CHECK_EQ(lossBufMetaIter->offset, frameOffset);
579 handleRetransmissionBufMetaWritten(
580 stream, frameOffset, frameLen, frameFin, lossBufMetaIter);
581 conn.lossState.totalBytesRetransmitted += frameLen;
582 VLOG(10) << nodeToString(conn.nodeType) << " sent retransmission"
583 << " packetNum=" << packetNum << " " << conn;
584 QUIC_STATS(conn.statsCallback, onPacketRetransmission);
585 return false;
586 }
587
updateConnection(QuicConnectionStateBase & conn,folly::Optional<PacketEvent> packetEvent,RegularQuicWritePacket packet,TimePoint sentTime,uint32_t encodedSize,uint32_t encodedBodySize,bool isDSRPacket)588 void updateConnection(
589 QuicConnectionStateBase& conn,
590 folly::Optional<PacketEvent> packetEvent,
591 RegularQuicWritePacket packet,
592 TimePoint sentTime,
593 uint32_t encodedSize,
594 uint32_t encodedBodySize,
595 bool isDSRPacket) {
596 auto packetNum = packet.header.getPacketSequenceNum();
597 // AckFrame, PaddingFrame and Datagrams are not retx-able.
598 bool retransmittable = false;
599 bool isHandshake = false;
600 bool isPing = false;
601 uint32_t connWindowUpdateSent = 0;
602 uint32_t ackFrameCounter = 0;
603 uint32_t streamBytesSent = 0;
604 uint32_t newStreamBytesSent = 0;
605 OutstandingPacket::Metadata::DetailsPerStream detailsPerStream;
606 auto packetNumberSpace = packet.header.getPacketNumberSpace();
607 bool isD6DProbe = packetNumberSpace == PacketNumberSpace::AppData &&
608 conn.d6d.lastProbe.hasValue() &&
609 conn.d6d.lastProbe->packetNum == packetNum;
610 VLOG(10) << nodeToString(conn.nodeType) << " sent packetNum=" << packetNum
611 << " in space=" << packetNumberSpace << " size=" << encodedSize
612 << " bodySize: " << encodedBodySize << " isDSR=" << isDSRPacket
613 << " " << conn;
614 if (conn.qLogger) {
615 conn.qLogger->addPacket(packet, encodedSize);
616 }
617 for (const auto& frame : packet.frames) {
618 switch (frame.type()) {
619 case QuicWriteFrame::Type::WriteStreamFrame: {
620 const WriteStreamFrame& writeStreamFrame = *frame.asWriteStreamFrame();
621 retransmittable = true;
622 auto stream = CHECK_NOTNULL(
623 conn.streamManager->getStream(writeStreamFrame.streamId));
624 bool newStreamDataWritten = false;
625 // TODO: Remove UNLIKELY here when DSR is ready for test.
626 if (UNLIKELY(writeStreamFrame.fromBufMeta)) {
627 newStreamDataWritten = handleStreamBufMetaWritten(
628 conn,
629 *stream,
630 writeStreamFrame.offset,
631 writeStreamFrame.len,
632 writeStreamFrame.fin,
633 packetNum,
634 packetNumberSpace);
635 } else {
636 newStreamDataWritten = handleStreamWritten(
637 conn,
638 *stream,
639 writeStreamFrame.offset,
640 writeStreamFrame.len,
641 writeStreamFrame.fin,
642 packetNum,
643 packetNumberSpace);
644 }
645 if (newStreamDataWritten) {
646 updateFlowControlOnWriteToSocket(*stream, writeStreamFrame.len);
647 maybeWriteBlockAfterSocketWrite(*stream);
648 maybeWriteDataBlockedAfterSocketWrite(conn);
649 conn.streamManager->addTx(writeStreamFrame.streamId);
650 newStreamBytesSent += writeStreamFrame.len;
651 }
652 conn.streamManager->updateWritableStreams(*stream);
653 conn.streamManager->updateLossStreams(*stream);
654 streamBytesSent += writeStreamFrame.len;
655 detailsPerStream.addFrame(writeStreamFrame, newStreamDataWritten);
656 break;
657 }
658 case QuicWriteFrame::Type::WriteCryptoFrame: {
659 const WriteCryptoFrame& writeCryptoFrame = *frame.asWriteCryptoFrame();
660 retransmittable = true;
661 auto protectionType = packet.header.getProtectionType();
662 // NewSessionTicket is sent in crypto frame encrypted with 1-rtt key,
663 // however, it is not part of handshake
664 isHandshake =
665 (protectionType == ProtectionType::Initial ||
666 protectionType == ProtectionType::Handshake);
667 auto encryptionLevel = protectionTypeToEncryptionLevel(protectionType);
668 handleStreamWritten(
669 conn,
670 *getCryptoStream(*conn.cryptoState, encryptionLevel),
671 writeCryptoFrame.offset,
672 writeCryptoFrame.len,
673 false /* fin */,
674 packetNum,
675 packetNumberSpace);
676 break;
677 }
678 case QuicWriteFrame::Type::WriteAckFrame: {
679 const WriteAckFrame& writeAckFrame = *frame.asWriteAckFrame();
680 DCHECK(!ackFrameCounter++)
681 << "Send more than one WriteAckFrame " << conn;
682 auto largestAckedPacketWritten = writeAckFrame.ackBlocks.front().end;
683 VLOG(10) << nodeToString(conn.nodeType)
684 << " sent packet with largestAcked="
685 << largestAckedPacketWritten << " packetNum=" << packetNum
686 << " " << conn;
687 updateAckSendStateOnSentPacketWithAcks(
688 conn,
689 getAckState(conn, packetNumberSpace),
690 largestAckedPacketWritten);
691 break;
692 }
693 case QuicWriteFrame::Type::RstStreamFrame: {
694 const RstStreamFrame& rstStreamFrame = *frame.asRstStreamFrame();
695 retransmittable = true;
696 VLOG(10) << nodeToString(conn.nodeType)
697 << " sent reset streams in packetNum=" << packetNum << " "
698 << conn;
699 auto resetIter =
700 conn.pendingEvents.resets.find(rstStreamFrame.streamId);
701 // TODO: this can happen because we clone RST_STREAM frames. Should we
702 // start to treat RST_STREAM in the same way we treat window update?
703 if (resetIter != conn.pendingEvents.resets.end()) {
704 conn.pendingEvents.resets.erase(resetIter);
705 } else {
706 DCHECK(packetEvent.has_value())
707 << " reset missing from pendingEvents for non-clone packet";
708 }
709 break;
710 }
711 case QuicWriteFrame::Type::MaxDataFrame: {
712 const MaxDataFrame& maxDataFrame = *frame.asMaxDataFrame();
713 CHECK(!connWindowUpdateSent++)
714 << "Send more than one connection window update " << conn;
715 VLOG(10) << nodeToString(conn.nodeType)
716 << " sent conn window update packetNum=" << packetNum << " "
717 << conn;
718 retransmittable = true;
719 VLOG(10) << nodeToString(conn.nodeType)
720 << " sent conn window update in packetNum=" << packetNum << " "
721 << conn;
722 onConnWindowUpdateSent(conn, maxDataFrame.maximumData, sentTime);
723 break;
724 }
725 case QuicWriteFrame::Type::DataBlockedFrame: {
726 VLOG(10) << nodeToString(conn.nodeType)
727 << " sent conn data blocked frame=" << packetNum << " "
728 << conn;
729 retransmittable = true;
730 conn.pendingEvents.sendDataBlocked = false;
731 break;
732 }
733 case QuicWriteFrame::Type::MaxStreamDataFrame: {
734 const MaxStreamDataFrame& maxStreamDataFrame =
735 *frame.asMaxStreamDataFrame();
736 auto stream = CHECK_NOTNULL(
737 conn.streamManager->getStream(maxStreamDataFrame.streamId));
738 retransmittable = true;
739 VLOG(10) << nodeToString(conn.nodeType)
740 << " sent packet with window update packetNum=" << packetNum
741 << " stream=" << maxStreamDataFrame.streamId << " " << conn;
742 onStreamWindowUpdateSent(
743 *stream, maxStreamDataFrame.maximumData, sentTime);
744 break;
745 }
746 case QuicWriteFrame::Type::StreamDataBlockedFrame: {
747 const StreamDataBlockedFrame& streamBlockedFrame =
748 *frame.asStreamDataBlockedFrame();
749 VLOG(10) << nodeToString(conn.nodeType)
750 << " sent blocked stream frame packetNum=" << packetNum << " "
751 << conn;
752 retransmittable = true;
753 conn.streamManager->removeBlocked(streamBlockedFrame.streamId);
754 break;
755 }
756 case QuicWriteFrame::Type::PingFrame:
757 // If this is a d6d probe, the it does not consume the sendPing request
758 // from application, because this packet, albeit containing a ping
759 // frame, is larger than the current PMTU and will potentially get
760 // dropped in the path. Additionally, the loss of this packet will not
761 // trigger retransmission, therefore tying it with the sendPing event
762 // will make this api unreliable.
763 if (!isD6DProbe) {
764 conn.pendingEvents.sendPing = false;
765 }
766 isPing = true;
767 break;
768 case QuicWriteFrame::Type::QuicSimpleFrame: {
769 const QuicSimpleFrame& simpleFrame = *frame.asQuicSimpleFrame();
770 retransmittable = true;
771 // We don't want this triggered for cloned frames.
772 if (!packetEvent.has_value()) {
773 updateSimpleFrameOnPacketSent(conn, simpleFrame);
774 }
775 break;
776 }
777 case QuicWriteFrame::Type::PaddingFrame: {
778 // do not mark padding as retransmittable. There are several reasons
779 // for this:
780 // 1. We might need to pad ACK packets to make it so that we can
781 // sample them correctly for header encryption. ACK packets may not
782 // count towards congestion window, so the padding frames in those
783 // ack packets should not count towards the window either
784 // 2. Of course we do not want to retransmit the ACK frames.
785 break;
786 }
787 case QuicWriteFrame::Type::DatagramFrame: {
788 // do not mark Datagram frames as retransmittable
789 break;
790 }
791 default:
792 retransmittable = true;
793 }
794 }
795
796 increaseNextPacketNum(conn, packetNumberSpace);
797 conn.lossState.largestSent =
798 std::max(conn.lossState.largestSent.value_or(packetNum), packetNum);
799 // updateConnection may be called multiple times during write. If before or
800 // during any updateConnection, setLossDetectionAlarm is already set, we
801 // shouldn't clear it:
802 if (!conn.pendingEvents.setLossDetectionAlarm) {
803 conn.pendingEvents.setLossDetectionAlarm = retransmittable;
804 }
805 conn.lossState.totalBytesSent += encodedSize;
806 conn.lossState.totalBodyBytesSent += encodedBodySize;
807 conn.lossState.totalPacketsSent++;
808 conn.lossState.totalStreamBytesSent += streamBytesSent;
809 conn.lossState.totalNewStreamBytesSent += newStreamBytesSent;
810
811 if (!retransmittable && !isPing) {
812 DCHECK(!packetEvent);
813 return;
814 }
815 conn.lossState.totalAckElicitingPacketsSent++;
816
817 auto packetIt =
818 std::find_if(
819 conn.outstandings.packets.rbegin(),
820 conn.outstandings.packets.rend(),
821 [packetNum](const auto& packetWithTime) {
822 return packetWithTime.packet.header.getPacketSequenceNum() <
823 packetNum;
824 })
825 .base();
826 auto& pkt = *conn.outstandings.packets.emplace(
827 packetIt,
828 std::move(packet),
829 sentTime,
830 encodedSize,
831 encodedBodySize,
832 isHandshake,
833 isD6DProbe,
834 // these numbers should all _include_ the current packet
835 // conn.lossState.inflightBytes isn't updated until below
836 // conn.outstandings.numOutstanding() + 1 since we're emplacing here
837 conn.lossState.totalBytesSent,
838 conn.lossState.totalBodyBytesSent,
839 conn.lossState.inflightBytes + encodedSize,
840 conn.outstandings.numOutstanding() + 1,
841 conn.lossState,
842 conn.writeCount,
843 std::move(detailsPerStream));
844
845 if (isD6DProbe) {
846 ++conn.d6d.outstandingProbes;
847 ++conn.d6d.meta.totalTxedProbes;
848 }
849 pkt.isAppLimited = conn.congestionController
850 ? conn.congestionController->isAppLimited()
851 : false;
852 if (conn.lossState.lastAckedTime.has_value() &&
853 conn.lossState.lastAckedPacketSentTime.has_value()) {
854 pkt.lastAckedPacketInfo.emplace(
855 *conn.lossState.lastAckedPacketSentTime,
856 *conn.lossState.lastAckedTime,
857 *conn.lossState.adjustedLastAckedTime,
858 conn.lossState.totalBytesSentAtLastAck,
859 conn.lossState.totalBytesAckedAtLastAck);
860 }
861 if (packetEvent) {
862 DCHECK(conn.outstandings.packetEvents.count(*packetEvent));
863 pkt.associatedEvent = std::move(packetEvent);
864 conn.lossState.totalBytesCloned += encodedSize;
865 }
866 pkt.isDSRPacket = isDSRPacket;
867 if (isDSRPacket) {
868 ++conn.outstandings.dsrCount;
869 }
870
871 if (conn.congestionController) {
872 conn.congestionController->onPacketSent(pkt);
873 }
874 if (conn.pacer) {
875 conn.pacer->onPacketSent();
876 }
877 if (conn.pathValidationLimiter &&
878 (conn.pendingEvents.pathChallenge || conn.outstandingPathValidation)) {
879 conn.pathValidationLimiter->onPacketSent(pkt.metadata.encodedSize);
880 }
881 conn.lossState.lastRetransmittablePacketSentTime = pkt.metadata.time;
882 if (pkt.associatedEvent) {
883 ++conn.outstandings.clonedPacketCount[packetNumberSpace];
884 ++conn.lossState.timeoutBasedRtxCount;
885 } else {
886 ++conn.outstandings.packetCount[packetNumberSpace];
887 }
888 }
889
congestionControlWritableBytes(const QuicConnectionStateBase & conn)890 uint64_t congestionControlWritableBytes(const QuicConnectionStateBase& conn) {
891 uint64_t writableBytes = std::numeric_limits<uint64_t>::max();
892
893 if (conn.pendingEvents.pathChallenge || conn.outstandingPathValidation) {
894 CHECK(conn.pathValidationLimiter);
895 // 0-RTT and path validation rate limiting should be mutually exclusive.
896 CHECK(!conn.writableBytesLimit);
897
898 // Use the default RTT measurement when starting a new path challenge (CC is
899 // reset). This shouldn't be an RTT sample, so we do not update the CC with
900 // this value.
901 writableBytes = conn.pathValidationLimiter->currentCredit(
902 std::chrono::steady_clock::now(),
903 conn.lossState.srtt == 0us ? kDefaultInitialRtt : conn.lossState.srtt);
904 } else if (conn.writableBytesLimit) {
905 if (*conn.writableBytesLimit <= conn.lossState.totalBytesSent) {
906 return 0;
907 }
908 writableBytes = *conn.writableBytesLimit - conn.lossState.totalBytesSent;
909 }
910
911 if (conn.congestionController) {
912 writableBytes = std::min<uint64_t>(
913 writableBytes, conn.congestionController->getWritableBytes());
914 }
915
916 if (writableBytes == std::numeric_limits<uint64_t>::max()) {
917 return writableBytes;
918 }
919
920 // For real-CC/PathChallenge cases, round the result up to the nearest
921 // multiple of udpSendPacketLen.
922 return (writableBytes + conn.udpSendPacketLen - 1) / conn.udpSendPacketLen *
923 conn.udpSendPacketLen;
924 }
925
unlimitedWritableBytes(const QuicConnectionStateBase &)926 uint64_t unlimitedWritableBytes(const QuicConnectionStateBase&) {
927 return std::numeric_limits<uint64_t>::max();
928 }
929
LongHeaderBuilder(LongHeader::Types packetType)930 HeaderBuilder LongHeaderBuilder(LongHeader::Types packetType) {
931 return [packetType](
932 const ConnectionId& srcConnId,
933 const ConnectionId& dstConnId,
934 PacketNum packetNum,
935 QuicVersion version,
936 const std::string& token) {
937 return LongHeader(
938 packetType, srcConnId, dstConnId, packetNum, version, token);
939 };
940 }
941
ShortHeaderBuilder()942 HeaderBuilder ShortHeaderBuilder() {
943 return [](const ConnectionId& /* srcConnId */,
944 const ConnectionId& dstConnId,
945 PacketNum packetNum,
946 QuicVersion,
947 const std::string&) {
948 return ShortHeader(ProtectionType::KeyPhaseZero, dstConnId, packetNum);
949 };
950 }
951
writeCryptoAndAckDataToSocket(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,LongHeader::Types packetType,Aead & cleartextCipher,const PacketNumberCipher & headerCipher,QuicVersion version,uint64_t packetLimit,const std::string & token)952 WriteQuicDataResult writeCryptoAndAckDataToSocket(
953 folly::AsyncUDPSocket& sock,
954 QuicConnectionStateBase& connection,
955 const ConnectionId& srcConnId,
956 const ConnectionId& dstConnId,
957 LongHeader::Types packetType,
958 Aead& cleartextCipher,
959 const PacketNumberCipher& headerCipher,
960 QuicVersion version,
961 uint64_t packetLimit,
962 const std::string& token) {
963 auto encryptionLevel = protectionTypeToEncryptionLevel(
964 longHeaderTypeToProtectionType(packetType));
965 FrameScheduler scheduler =
966 std::move(FrameScheduler::Builder(
967 connection,
968 encryptionLevel,
969 LongHeader::typeToPacketNumberSpace(packetType),
970 "CryptoAndAcksScheduler")
971 .ackFrames()
972 .cryptoFrames())
973 .build();
974 auto builder = LongHeaderBuilder(packetType);
975 WriteQuicDataResult result;
976 auto& packetsWritten = result.packetsWritten;
977 auto& probesWritten = result.probesWritten;
978 auto& cryptoStream =
979 *getCryptoStream(*connection.cryptoState, encryptionLevel);
980 auto& numProbePackets =
981 connection.pendingEvents
982 .numProbePackets[LongHeader::typeToPacketNumberSpace(packetType)];
983 if (numProbePackets &&
984 (cryptoStream.retransmissionBuffer.size() || scheduler.hasData())) {
985 probesWritten = writeProbingDataToSocket(
986 sock,
987 connection,
988 srcConnId,
989 dstConnId,
990 builder,
991 encryptionLevel,
992 LongHeader::typeToPacketNumberSpace(packetType),
993 scheduler,
994 numProbePackets, // This possibly bypasses the packetLimit.
995 cleartextCipher,
996 headerCipher,
997 version,
998 token);
999 }
1000 packetLimit = probesWritten > packetLimit ? 0 : (packetLimit - probesWritten);
1001 // Only get one chance to write probes.
1002 numProbePackets = 0;
1003 // Crypto data is written without aead protection.
1004 packetsWritten += writeConnectionDataToSocket(
1005 sock,
1006 connection,
1007 srcConnId,
1008 dstConnId,
1009 std::move(builder),
1010 LongHeader::typeToPacketNumberSpace(packetType),
1011 scheduler,
1012 congestionControlWritableBytes,
1013 packetLimit - packetsWritten,
1014 cleartextCipher,
1015 headerCipher,
1016 version,
1017 token);
1018 VLOG_IF(10, packetsWritten || probesWritten)
1019 << nodeToString(connection.nodeType)
1020 << " written crypto and acks data type=" << packetType
1021 << " packetsWritten=" << packetsWritten
1022 << " probesWritten=" << probesWritten << connection;
1023 CHECK_GE(packetLimit, packetsWritten);
1024 return result;
1025 }
1026
writeQuicDataToSocket(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,uint64_t packetLimit)1027 WriteQuicDataResult writeQuicDataToSocket(
1028 folly::AsyncUDPSocket& sock,
1029 QuicConnectionStateBase& connection,
1030 const ConnectionId& srcConnId,
1031 const ConnectionId& dstConnId,
1032 const Aead& aead,
1033 const PacketNumberCipher& headerCipher,
1034 QuicVersion version,
1035 uint64_t packetLimit) {
1036 return writeQuicDataToSocketImpl(
1037 sock,
1038 connection,
1039 srcConnId,
1040 dstConnId,
1041 aead,
1042 headerCipher,
1043 version,
1044 packetLimit,
1045 /*exceptCryptoStream=*/false);
1046 }
1047
writeQuicDataExceptCryptoStreamToSocket(folly::AsyncUDPSocket & socket,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,uint64_t packetLimit)1048 WriteQuicDataResult writeQuicDataExceptCryptoStreamToSocket(
1049 folly::AsyncUDPSocket& socket,
1050 QuicConnectionStateBase& connection,
1051 const ConnectionId& srcConnId,
1052 const ConnectionId& dstConnId,
1053 const Aead& aead,
1054 const PacketNumberCipher& headerCipher,
1055 QuicVersion version,
1056 uint64_t packetLimit) {
1057 return writeQuicDataToSocketImpl(
1058 socket,
1059 connection,
1060 srcConnId,
1061 dstConnId,
1062 aead,
1063 headerCipher,
1064 version,
1065 packetLimit,
1066 /*exceptCryptoStream=*/true);
1067 }
1068
writeZeroRttDataToSocket(folly::AsyncUDPSocket & socket,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,uint64_t packetLimit)1069 uint64_t writeZeroRttDataToSocket(
1070 folly::AsyncUDPSocket& socket,
1071 QuicConnectionStateBase& connection,
1072 const ConnectionId& srcConnId,
1073 const ConnectionId& dstConnId,
1074 const Aead& aead,
1075 const PacketNumberCipher& headerCipher,
1076 QuicVersion version,
1077 uint64_t packetLimit) {
1078 auto type = LongHeader::Types::ZeroRtt;
1079 auto encryptionLevel =
1080 protectionTypeToEncryptionLevel(longHeaderTypeToProtectionType(type));
1081 auto builder = LongHeaderBuilder(type);
1082 // Probe is not useful for zero rtt because we will always have handshake
1083 // packets outstanding when sending zero rtt data.
1084 FrameScheduler scheduler =
1085 std::move(FrameScheduler::Builder(
1086 connection,
1087 encryptionLevel,
1088 LongHeader::typeToPacketNumberSpace(type),
1089 "ZeroRttScheduler")
1090 .streamFrames()
1091 .resetFrames()
1092 .windowUpdateFrames()
1093 .blockedFrames()
1094 .simpleFrames())
1095 .build();
1096 auto written = writeConnectionDataToSocket(
1097 socket,
1098 connection,
1099 srcConnId,
1100 dstConnId,
1101 std::move(builder),
1102 LongHeader::typeToPacketNumberSpace(type),
1103 scheduler,
1104 congestionControlWritableBytes,
1105 packetLimit,
1106 aead,
1107 headerCipher,
1108 version);
1109 VLOG_IF(10, written > 0) << nodeToString(connection.nodeType)
1110 << " written zero rtt data, packets=" << written
1111 << " " << connection;
1112 DCHECK_GE(packetLimit, written);
1113 return written;
1114 }
1115
writeCloseCommon(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,PacketHeader && header,folly::Optional<std::pair<QuicErrorCode,std::string>> closeDetails,const Aead & aead,const PacketNumberCipher & headerCipher)1116 void writeCloseCommon(
1117 folly::AsyncUDPSocket& sock,
1118 QuicConnectionStateBase& connection,
1119 PacketHeader&& header,
1120 folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
1121 const Aead& aead,
1122 const PacketNumberCipher& headerCipher) {
1123 // close is special, we're going to bypass all the packet sent logic for all
1124 // packets we send with a connection close frame.
1125 PacketNumberSpace pnSpace = header.getPacketNumberSpace();
1126 HeaderForm headerForm = header.getHeaderForm();
1127 PacketNum packetNum = header.getPacketSequenceNum();
1128 // TODO: This too needs to be switchable between regular and inplace builder.
1129 RegularQuicPacketBuilder packetBuilder(
1130 kDefaultUDPSendPacketLen,
1131 std::move(header),
1132 getAckState(connection, pnSpace).largestAckedByPeer.value_or(0));
1133 packetBuilder.encodePacketHeader();
1134 packetBuilder.accountForCipherOverhead(aead.getCipherOverhead());
1135 size_t written = 0;
1136 if (!closeDetails) {
1137 written = writeFrame(
1138 ConnectionCloseFrame(
1139 QuicErrorCode(TransportErrorCode::NO_ERROR),
1140 std::string("No error")),
1141 packetBuilder);
1142 } else {
1143 switch (closeDetails->first.type()) {
1144 case QuicErrorCode::Type::ApplicationErrorCode:
1145 written = writeFrame(
1146 ConnectionCloseFrame(
1147 QuicErrorCode(*closeDetails->first.asApplicationErrorCode()),
1148 closeDetails->second,
1149 quic::FrameType::CONNECTION_CLOSE_APP_ERR),
1150 packetBuilder);
1151 break;
1152 case QuicErrorCode::Type::TransportErrorCode:
1153 written = writeFrame(
1154 ConnectionCloseFrame(
1155 QuicErrorCode(*closeDetails->first.asTransportErrorCode()),
1156 closeDetails->second,
1157 quic::FrameType::CONNECTION_CLOSE),
1158 packetBuilder);
1159 break;
1160 case QuicErrorCode::Type::LocalErrorCode:
1161 written = writeFrame(
1162 ConnectionCloseFrame(
1163 QuicErrorCode(TransportErrorCode::INTERNAL_ERROR),
1164 std::string("Internal error"),
1165 quic::FrameType::CONNECTION_CLOSE),
1166 packetBuilder);
1167 break;
1168 }
1169 }
1170 if (pnSpace == PacketNumberSpace::Initial &&
1171 connection.nodeType == QuicNodeType::Client) {
1172 while (packetBuilder.remainingSpaceInPkt() > 0) {
1173 writeFrame(PaddingFrame(), packetBuilder);
1174 }
1175 }
1176 if (written == 0) {
1177 LOG(ERROR) << "Close frame too large " << connection;
1178 return;
1179 }
1180 auto packet = std::move(packetBuilder).buildPacket();
1181 packet.header->coalesce();
1182 packet.body->reserve(0, aead.getCipherOverhead());
1183 CHECK_GE(packet.body->tailroom(), aead.getCipherOverhead());
1184 auto body = aead.inplaceEncrypt(
1185 std::move(packet.body), packet.header.get(), packetNum);
1186 body->coalesce();
1187 encryptPacketHeader(
1188 headerForm,
1189 packet.header->writableData(),
1190 packet.header->length(),
1191 body->data(),
1192 body->length(),
1193 headerCipher);
1194 auto packetBuf = std::move(packet.header);
1195 packetBuf->prependChain(std::move(body));
1196 auto packetSize = packetBuf->computeChainDataLength();
1197 if (connection.qLogger) {
1198 connection.qLogger->addPacket(packet.packet, packetSize);
1199 }
1200 VLOG(10) << nodeToString(connection.nodeType)
1201 << " sent close packetNum=" << packetNum << " in space=" << pnSpace
1202 << " " << connection;
1203 // Increment the sequence number.
1204 increaseNextPacketNum(connection, pnSpace);
1205 // best effort writing to the socket, ignore any errors.
1206 auto ret = sock.write(connection.peerAddress, packetBuf);
1207 connection.lossState.totalBytesSent += packetSize;
1208 if (ret < 0) {
1209 VLOG(4) << "Error writing connection close " << folly::errnoStr(errno)
1210 << " " << connection;
1211 } else {
1212 QUIC_STATS(connection.statsCallback, onWrite, ret);
1213 }
1214 }
1215
writeLongClose(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,LongHeader::Types headerType,folly::Optional<std::pair<QuicErrorCode,std::string>> closeDetails,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version)1216 void writeLongClose(
1217 folly::AsyncUDPSocket& sock,
1218 QuicConnectionStateBase& connection,
1219 const ConnectionId& srcConnId,
1220 const ConnectionId& dstConnId,
1221 LongHeader::Types headerType,
1222 folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
1223 const Aead& aead,
1224 const PacketNumberCipher& headerCipher,
1225 QuicVersion version) {
1226 if (!connection.serverConnectionId) {
1227 // It's possible that servers encountered an error before binding to a
1228 // connection id.
1229 return;
1230 }
1231 LongHeader header(
1232 headerType,
1233 srcConnId,
1234 dstConnId,
1235 getNextPacketNum(
1236 connection, LongHeader::typeToPacketNumberSpace(headerType)),
1237 version);
1238 writeCloseCommon(
1239 sock,
1240 connection,
1241 std::move(header),
1242 std::move(closeDetails),
1243 aead,
1244 headerCipher);
1245 }
1246
writeShortClose(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & connId,folly::Optional<std::pair<QuicErrorCode,std::string>> closeDetails,const Aead & aead,const PacketNumberCipher & headerCipher)1247 void writeShortClose(
1248 folly::AsyncUDPSocket& sock,
1249 QuicConnectionStateBase& connection,
1250 const ConnectionId& connId,
1251 folly::Optional<std::pair<QuicErrorCode, std::string>> closeDetails,
1252 const Aead& aead,
1253 const PacketNumberCipher& headerCipher) {
1254 auto header = ShortHeader(
1255 ProtectionType::KeyPhaseZero,
1256 connId,
1257 getNextPacketNum(connection, PacketNumberSpace::AppData));
1258 writeCloseCommon(
1259 sock,
1260 connection,
1261 std::move(header),
1262 std::move(closeDetails),
1263 aead,
1264 headerCipher);
1265 }
1266
encryptPacketHeader(HeaderForm headerForm,uint8_t * header,size_t headerLen,const uint8_t * encryptedBody,size_t bodyLen,const PacketNumberCipher & headerCipher)1267 void encryptPacketHeader(
1268 HeaderForm headerForm,
1269 uint8_t* header,
1270 size_t headerLen,
1271 const uint8_t* encryptedBody,
1272 size_t bodyLen,
1273 const PacketNumberCipher& headerCipher) {
1274 // Header encryption.
1275 auto packetNumberLength = parsePacketNumberLength(*header);
1276 Sample sample;
1277 size_t sampleBytesToUse = kMaxPacketNumEncodingSize - packetNumberLength;
1278 // If there were less than 4 bytes in the packet number, some of the payload
1279 // bytes will also be skipped during sampling.
1280 CHECK_GE(bodyLen, sampleBytesToUse + sample.size());
1281 encryptedBody += sampleBytesToUse;
1282 memcpy(sample.data(), encryptedBody, sample.size());
1283
1284 folly::MutableByteRange initialByteRange(header, 1);
1285 folly::MutableByteRange packetNumByteRange(
1286 header + headerLen - packetNumberLength, packetNumberLength);
1287 if (headerForm == HeaderForm::Short) {
1288 headerCipher.encryptShortHeader(
1289 sample, initialByteRange, packetNumByteRange);
1290 } else {
1291 headerCipher.encryptLongHeader(
1292 sample, initialByteRange, packetNumByteRange);
1293 }
1294 }
1295
writeConnectionDataToSocket(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,HeaderBuilder builder,PacketNumberSpace pnSpace,QuicPacketScheduler & scheduler,const WritableBytesFunc & writableBytesFunc,uint64_t packetLimit,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,const std::string & token)1296 uint64_t writeConnectionDataToSocket(
1297 folly::AsyncUDPSocket& sock,
1298 QuicConnectionStateBase& connection,
1299 const ConnectionId& srcConnId,
1300 const ConnectionId& dstConnId,
1301 HeaderBuilder builder,
1302 PacketNumberSpace pnSpace,
1303 QuicPacketScheduler& scheduler,
1304 const WritableBytesFunc& writableBytesFunc,
1305 uint64_t packetLimit,
1306 const Aead& aead,
1307 const PacketNumberCipher& headerCipher,
1308 QuicVersion version,
1309 const std::string& token) {
1310 VLOG(10) << nodeToString(connection.nodeType)
1311 << " writing data using scheduler=" << scheduler.name() << " "
1312 << connection;
1313
1314 auto batchWriter = BatchWriterFactory::makeBatchWriter(
1315 sock,
1316 connection.transportSettings.batchingMode,
1317 connection.transportSettings.maxBatchSize,
1318 connection.transportSettings.useThreadLocalBatching,
1319 connection.transportSettings.threadLocalDelay,
1320 connection.transportSettings.dataPathType,
1321 connection);
1322
1323 auto happyEyeballsState = connection.nodeType == QuicNodeType::Server
1324 ? nullptr
1325 : &static_cast<QuicClientConnectionState&>(connection).happyEyeballsState;
1326 IOBufQuicBatch ioBufBatch(
1327 std::move(batchWriter),
1328 connection.transportSettings.useThreadLocalBatching,
1329 sock,
1330 connection.peerAddress,
1331 connection.statsCallback,
1332 happyEyeballsState);
1333
1334 if (connection.loopDetectorCallback) {
1335 connection.writeDebugState.schedulerName = scheduler.name().str();
1336 connection.writeDebugState.noWriteReason = NoWriteReason::WRITE_OK;
1337 if (!scheduler.hasData()) {
1338 connection.writeDebugState.noWriteReason = NoWriteReason::EMPTY_SCHEDULER;
1339 }
1340 }
1341 auto writeLoopBeginTime = Clock::now();
1342 auto batchSize = connection.transportSettings.batchingMode ==
1343 QuicBatchingMode::BATCHING_MODE_NONE
1344 ? connection.transportSettings.writeConnectionDataPacketsLimit
1345 : connection.transportSettings.maxBatchSize;
1346 while (scheduler.hasData() && ioBufBatch.getPktSent() < packetLimit &&
1347 ((ioBufBatch.getPktSent() < batchSize) ||
1348 writeLoopTimeLimit(writeLoopBeginTime, connection))) {
1349 auto packetNum = getNextPacketNum(connection, pnSpace);
1350 auto header = builder(srcConnId, dstConnId, packetNum, version, token);
1351 uint32_t writableBytes = folly::to<uint32_t>(std::min<uint64_t>(
1352 connection.udpSendPacketLen, writableBytesFunc(connection)));
1353 uint64_t cipherOverhead = aead.getCipherOverhead();
1354 if (writableBytes < cipherOverhead) {
1355 writableBytes = 0;
1356 } else {
1357 writableBytes -= cipherOverhead;
1358 }
1359
1360 const auto& dataPlainFunc =
1361 connection.transportSettings.dataPathType == DataPathType::ChainedMemory
1362 ? iobufChainBasedBuildScheduleEncrypt
1363 : continuousMemoryBuildScheduleEncrypt;
1364 auto ret = dataPlainFunc(
1365 connection,
1366 std::move(header),
1367 pnSpace,
1368 packetNum,
1369 cipherOverhead,
1370 scheduler,
1371 writableBytes,
1372 ioBufBatch,
1373 aead,
1374 headerCipher);
1375
1376 if (!ret.buildSuccess) {
1377 return ioBufBatch.getPktSent();
1378 }
1379
1380 // If we build a packet, we updateConnection(), even if write might have
1381 // been failed. Because if it builds, a lot of states need to be updated no
1382 // matter the write result. We are basically treating this case as if we
1383 // pretend write was also successful but packet is lost somewhere in the
1384 // network.
1385 auto& result = ret.result;
1386 updateConnection(
1387 connection,
1388 std::move(result->packetEvent),
1389 std::move(result->packet->packet),
1390 Clock::now(),
1391 folly::to<uint32_t>(ret.encodedSize),
1392 folly::to<uint32_t>(ret.encodedBodySize),
1393 false /* isDSRPacket */);
1394
1395 // if ioBufBatch.write returns false
1396 // it is because a flush() call failed
1397 if (!ret.writeSuccess) {
1398 if (connection.loopDetectorCallback) {
1399 connection.writeDebugState.noWriteReason =
1400 NoWriteReason::SOCKET_FAILURE;
1401 }
1402 return ioBufBatch.getPktSent();
1403 }
1404 }
1405
1406 ioBufBatch.flush();
1407 if (connection.transportSettings.dataPathType ==
1408 DataPathType::ContinuousMemory) {
1409 CHECK(connection.bufAccessor->ownsBuffer());
1410 auto buf = connection.bufAccessor->obtain();
1411 CHECK(buf->length() == 0 && buf->headroom() == 0);
1412 connection.bufAccessor->release(std::move(buf));
1413 }
1414 return ioBufBatch.getPktSent();
1415 }
1416
writeProbingDataToSocket(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const HeaderBuilder & builder,EncryptionLevel encryptionLevel,PacketNumberSpace pnSpace,FrameScheduler scheduler,uint8_t probesToSend,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version,const std::string & token)1417 uint64_t writeProbingDataToSocket(
1418 folly::AsyncUDPSocket& sock,
1419 QuicConnectionStateBase& connection,
1420 const ConnectionId& srcConnId,
1421 const ConnectionId& dstConnId,
1422 const HeaderBuilder& builder,
1423 EncryptionLevel encryptionLevel,
1424 PacketNumberSpace pnSpace,
1425 FrameScheduler scheduler,
1426 uint8_t probesToSend,
1427 const Aead& aead,
1428 const PacketNumberCipher& headerCipher,
1429 QuicVersion version,
1430 const std::string& token) {
1431 // Skip a packet number for probing packets to elicit acks
1432 increaseNextPacketNum(connection, pnSpace);
1433 CloningScheduler cloningScheduler(
1434 scheduler, connection, "CloningScheduler", aead.getCipherOverhead());
1435 auto written = writeConnectionDataToSocket(
1436 sock,
1437 connection,
1438 srcConnId,
1439 dstConnId,
1440 builder,
1441 pnSpace,
1442 cloningScheduler,
1443 unlimitedWritableBytes,
1444 probesToSend,
1445 aead,
1446 headerCipher,
1447 version,
1448 token);
1449 if (probesToSend && !written) {
1450 // Fall back to send a ping:
1451 connection.pendingEvents.sendPing = true;
1452 auto pingScheduler =
1453 std::move(FrameScheduler::Builder(
1454 connection, encryptionLevel, pnSpace, "PingScheduler")
1455 .pingFrames())
1456 .build();
1457 written += writeConnectionDataToSocket(
1458 sock,
1459 connection,
1460 srcConnId,
1461 dstConnId,
1462 builder,
1463 pnSpace,
1464 pingScheduler,
1465 unlimitedWritableBytes,
1466 probesToSend - written,
1467 aead,
1468 headerCipher,
1469 version);
1470 }
1471 VLOG_IF(10, written > 0)
1472 << nodeToString(connection.nodeType)
1473 << " writing probes using scheduler=CloningScheduler " << connection;
1474 return written;
1475 }
1476
writeD6DProbeToSocket(folly::AsyncUDPSocket & sock,QuicConnectionStateBase & connection,const ConnectionId & srcConnId,const ConnectionId & dstConnId,const Aead & aead,const PacketNumberCipher & headerCipher,QuicVersion version)1477 uint64_t writeD6DProbeToSocket(
1478 folly::AsyncUDPSocket& sock,
1479 QuicConnectionStateBase& connection,
1480 const ConnectionId& srcConnId,
1481 const ConnectionId& dstConnId,
1482 const Aead& aead,
1483 const PacketNumberCipher& headerCipher,
1484 QuicVersion version) {
1485 if (!connection.pendingEvents.d6d.sendProbePacket) {
1486 return 0;
1487 }
1488 auto builder = ShortHeaderBuilder();
1489 // D6D probe is always in AppData pnSpace
1490 auto pnSpace = PacketNumberSpace::AppData;
1491 // Skip a packet number for probing packets to elicit acks
1492 increaseNextPacketNum(connection, pnSpace);
1493 D6DProbeScheduler d6dProbeScheduler(
1494 connection,
1495 "D6DProbeScheduler",
1496 aead.getCipherOverhead(),
1497 connection.d6d.currentProbeSize);
1498 auto written = writeConnectionDataToSocket(
1499 sock,
1500 connection,
1501 srcConnId,
1502 dstConnId,
1503 builder,
1504 pnSpace,
1505 d6dProbeScheduler,
1506 unlimitedWritableBytes,
1507 1,
1508 aead,
1509 headerCipher,
1510 version);
1511 VLOG_IF(10, written > 0) << nodeToString(connection.nodeType)
1512 << " writing d6d probes using scheduler=D6DScheduler"
1513 << connection;
1514 if (written > 0) {
1515 connection.pendingEvents.d6d.sendProbePacket = false;
1516 }
1517 return written;
1518 }
1519
shouldWriteData(const QuicConnectionStateBase & conn)1520 WriteDataReason shouldWriteData(const QuicConnectionStateBase& conn) {
1521 auto& numProbePackets = conn.pendingEvents.numProbePackets;
1522 bool shouldWriteInitialProbes =
1523 numProbePackets[PacketNumberSpace::Initial] && conn.initialWriteCipher;
1524 bool shouldWriteHandshakeProbes =
1525 numProbePackets[PacketNumberSpace::Handshake] &&
1526 conn.handshakeWriteCipher;
1527 bool shouldWriteAppDataProbes =
1528 numProbePackets[PacketNumberSpace::AppData] && conn.oneRttWriteCipher;
1529 if (shouldWriteInitialProbes || shouldWriteHandshakeProbes ||
1530 shouldWriteAppDataProbes) {
1531 VLOG(10) << nodeToString(conn.nodeType) << " needs write because of PTO"
1532 << conn;
1533 return WriteDataReason::PROBES;
1534 }
1535 if (hasAckDataToWrite(conn)) {
1536 VLOG(10) << nodeToString(conn.nodeType) << " needs write because of ACKs "
1537 << conn;
1538 return WriteDataReason::ACK;
1539 }
1540
1541 if (!congestionControlWritableBytes(conn)) {
1542 QUIC_STATS(conn.statsCallback, onCwndBlocked);
1543 return WriteDataReason::NO_WRITE;
1544 }
1545 return hasNonAckDataToWrite(conn);
1546 }
1547
hasAckDataToWrite(const QuicConnectionStateBase & conn)1548 bool hasAckDataToWrite(const QuicConnectionStateBase& conn) {
1549 // hasAcksToSchedule tells us whether we have acks.
1550 // needsToSendAckImmediately tells us when to schedule the acks. If we don't
1551 // have an immediate need to schedule the acks then we need to wait till we
1552 // satisfy a condition where there is immediate need, so we shouldn't
1553 // consider the acks to be writable.
1554 bool writeAcks =
1555 (toWriteInitialAcks(conn) || toWriteHandshakeAcks(conn) ||
1556 toWriteAppDataAcks(conn));
1557 VLOG_IF(10, writeAcks) << nodeToString(conn.nodeType)
1558 << " needs write because of acks largestAck="
1559 << largestAckToSendToString(conn) << " largestSentAck="
1560 << largestAckScheduledToString(conn)
1561 << " ackTimeoutSet="
1562 << conn.pendingEvents.scheduleAckTimeout << " "
1563 << conn;
1564 return writeAcks;
1565 }
1566
hasNonAckDataToWrite(const QuicConnectionStateBase & conn)1567 WriteDataReason hasNonAckDataToWrite(const QuicConnectionStateBase& conn) {
1568 if (cryptoHasWritableData(conn)) {
1569 VLOG(10) << nodeToString(conn.nodeType)
1570 << " needs write because of crypto stream"
1571 << " " << conn;
1572 return WriteDataReason::CRYPTO_STREAM;
1573 }
1574 if (!conn.oneRttWriteCipher &&
1575 !(conn.nodeType == QuicNodeType::Client &&
1576 static_cast<const QuicClientConnectionState&>(conn)
1577 .zeroRttWriteCipher)) {
1578 // All the rest of the types of data need either a 1-rtt or 0-rtt cipher to
1579 // be written.
1580 return WriteDataReason::NO_WRITE;
1581 }
1582 if (!conn.pendingEvents.resets.empty()) {
1583 return WriteDataReason::RESET;
1584 }
1585 if (conn.streamManager->hasWindowUpdates()) {
1586 return WriteDataReason::STREAM_WINDOW_UPDATE;
1587 }
1588 if (conn.pendingEvents.connWindowUpdate) {
1589 return WriteDataReason::CONN_WINDOW_UPDATE;
1590 }
1591 if (conn.streamManager->hasBlocked()) {
1592 return WriteDataReason::BLOCKED;
1593 }
1594 if (getSendConnFlowControlBytesWire(conn) != 0 &&
1595 conn.streamManager->hasWritable()) {
1596 return WriteDataReason::STREAM;
1597 }
1598 if (!conn.pendingEvents.frames.empty()) {
1599 return WriteDataReason::SIMPLE;
1600 }
1601 if ((conn.pendingEvents.pathChallenge != folly::none)) {
1602 return WriteDataReason::PATHCHALLENGE;
1603 }
1604 if (conn.pendingEvents.sendPing) {
1605 return WriteDataReason::PING;
1606 }
1607 if (!conn.datagramState.writeBuffer.empty()) {
1608 return WriteDataReason::DATAGRAM;
1609 }
1610 return WriteDataReason::NO_WRITE;
1611 }
1612
maybeSendStreamLimitUpdates(QuicConnectionStateBase & conn)1613 void maybeSendStreamLimitUpdates(QuicConnectionStateBase& conn) {
1614 auto update = conn.streamManager->remoteBidirectionalStreamLimitUpdate();
1615 if (update) {
1616 sendSimpleFrame(conn, (MaxStreamsFrame(*update, true)));
1617 }
1618 update = conn.streamManager->remoteUnidirectionalStreamLimitUpdate();
1619 if (update) {
1620 sendSimpleFrame(conn, (MaxStreamsFrame(*update, false)));
1621 }
1622 }
1623
implicitAckCryptoStream(QuicConnectionStateBase & conn,EncryptionLevel encryptionLevel)1624 void implicitAckCryptoStream(
1625 QuicConnectionStateBase& conn,
1626 EncryptionLevel encryptionLevel) {
1627 auto implicitAckTime = Clock::now();
1628 auto packetNumSpace = encryptionLevel == EncryptionLevel::Handshake
1629 ? PacketNumberSpace::Handshake
1630 : PacketNumberSpace::Initial;
1631 auto& ackState = getAckState(conn, packetNumSpace);
1632 AckBlocks ackBlocks;
1633 ReadAckFrame implicitAck;
1634 implicitAck.ackDelay = 0ms;
1635 implicitAck.implicit = true;
1636 for (const auto& op : conn.outstandings.packets) {
1637 if (op.packet.header.getPacketNumberSpace() == packetNumSpace) {
1638 ackBlocks.insert(op.packet.header.getPacketSequenceNum());
1639 }
1640 }
1641 if (ackBlocks.empty()) {
1642 return;
1643 }
1644 // Construct an implicit ack covering the entire range of packets.
1645 // If some of these have already been ACK'd then processAckFrame
1646 // should simply ignore them.
1647 implicitAck.largestAcked = ackBlocks.back().end;
1648 implicitAck.ackBlocks.emplace_back(
1649 ackBlocks.front().start, implicitAck.largestAcked);
1650 processAckFrame(
1651 conn,
1652 packetNumSpace,
1653 implicitAck,
1654 [&](auto&, auto& packetFrame, auto&) {
1655 switch (packetFrame.type()) {
1656 case QuicWriteFrame::Type::WriteCryptoFrame: {
1657 const WriteCryptoFrame& frame = *packetFrame.asWriteCryptoFrame();
1658 auto cryptoStream =
1659 getCryptoStream(*conn.cryptoState, encryptionLevel);
1660 processCryptoStreamAck(*cryptoStream, frame.offset, frame.len);
1661 break;
1662 }
1663 case QuicWriteFrame::Type::WriteAckFrame: {
1664 const WriteAckFrame& frame = *packetFrame.asWriteAckFrame();
1665 commonAckVisitorForAckFrame(ackState, frame);
1666 break;
1667 }
1668 default: {
1669 // We don't bother checking for valid packets, since these are
1670 // our outstanding packets.
1671 }
1672 }
1673 },
1674 // We shouldn't mark anything as lost from the implicit ACK, as it should
1675 // be ACKing the entire rangee.
1676 [](auto&, auto&, auto) {
1677 LOG(FATAL) << "Got loss from implicit crypto ACK.";
1678 },
1679 implicitAckTime);
1680 // Clear our the loss buffer explicity. The implicit ACK itself will not
1681 // remove data already in the loss buffer.
1682 auto cryptoStream = getCryptoStream(*conn.cryptoState, encryptionLevel);
1683 cryptoStream->lossBuffer.clear();
1684 CHECK(cryptoStream->retransmissionBuffer.empty());
1685 // The write buffer should be empty, there's no optional crypto data.
1686 CHECK(cryptoStream->writeBuffer.empty());
1687 }
1688
handshakeConfirmed(QuicConnectionStateBase & conn)1689 void handshakeConfirmed(QuicConnectionStateBase& conn) {
1690 // If we've supposedly confirmed the handshake and don't have the 1RTT
1691 // ciphers installed, we are going to have problems.
1692 CHECK(conn.oneRttWriteCipher);
1693 CHECK(conn.oneRttWriteHeaderCipher);
1694 CHECK(conn.readCodec->getOneRttReadCipher());
1695 CHECK(conn.readCodec->getOneRttHeaderCipher());
1696 conn.readCodec->onHandshakeDone(Clock::now());
1697 conn.initialWriteCipher.reset();
1698 conn.initialHeaderCipher.reset();
1699 conn.readCodec->setInitialReadCipher(nullptr);
1700 conn.readCodec->setInitialHeaderCipher(nullptr);
1701 implicitAckCryptoStream(conn, EncryptionLevel::Initial);
1702 conn.handshakeWriteCipher.reset();
1703 conn.handshakeWriteHeaderCipher.reset();
1704 conn.readCodec->setHandshakeReadCipher(nullptr);
1705 conn.readCodec->setHandshakeHeaderCipher(nullptr);
1706 implicitAckCryptoStream(conn, EncryptionLevel::Handshake);
1707 }
1708
hasInitialOrHandshakeCiphers(QuicConnectionStateBase & conn)1709 bool hasInitialOrHandshakeCiphers(QuicConnectionStateBase& conn) {
1710 return conn.initialWriteCipher || conn.handshakeWriteCipher ||
1711 conn.readCodec->getInitialCipher() ||
1712 conn.readCodec->getHandshakeReadCipher();
1713 }
1714
1715 } // namespace quic
1716