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