in quic/api/QuicTransportFunctions.cpp [1139:1237]
void writeCloseCommon(
folly::AsyncUDPSocket& sock,
QuicConnectionStateBase& connection,
PacketHeader&& header,
folly::Optional<QuicError> closeDetails,
const Aead& aead,
const PacketNumberCipher& headerCipher) {
// close is special, we're going to bypass all the packet sent logic for all
// packets we send with a connection close frame.
PacketNumberSpace pnSpace = header.getPacketNumberSpace();
HeaderForm headerForm = header.getHeaderForm();
PacketNum packetNum = header.getPacketSequenceNum();
// TODO: This too needs to be switchable between regular and inplace builder.
RegularQuicPacketBuilder packetBuilder(
kDefaultUDPSendPacketLen,
std::move(header),
getAckState(connection, pnSpace).largestAckedByPeer.value_or(0));
packetBuilder.encodePacketHeader();
packetBuilder.accountForCipherOverhead(aead.getCipherOverhead());
size_t written = 0;
if (!closeDetails) {
written = writeFrame(
ConnectionCloseFrame(
QuicErrorCode(TransportErrorCode::NO_ERROR),
std::string("No error")),
packetBuilder);
} else {
switch (closeDetails->code.type()) {
case QuicErrorCode::Type::ApplicationErrorCode:
written = writeFrame(
ConnectionCloseFrame(
QuicErrorCode(*closeDetails->code.asApplicationErrorCode()),
closeDetails->message,
quic::FrameType::CONNECTION_CLOSE_APP_ERR),
packetBuilder);
break;
case QuicErrorCode::Type::TransportErrorCode:
written = writeFrame(
ConnectionCloseFrame(
QuicErrorCode(*closeDetails->code.asTransportErrorCode()),
closeDetails->message,
quic::FrameType::CONNECTION_CLOSE),
packetBuilder);
break;
case QuicErrorCode::Type::LocalErrorCode:
written = writeFrame(
ConnectionCloseFrame(
QuicErrorCode(TransportErrorCode::INTERNAL_ERROR),
std::string("Internal error"),
quic::FrameType::CONNECTION_CLOSE),
packetBuilder);
break;
}
}
if (pnSpace == PacketNumberSpace::Initial &&
connection.nodeType == QuicNodeType::Client) {
while (packetBuilder.remainingSpaceInPkt() > 0) {
writeFrame(PaddingFrame(), packetBuilder);
}
}
if (written == 0) {
LOG(ERROR) << "Close frame too large " << connection;
return;
}
auto packet = std::move(packetBuilder).buildPacket();
packet.header->coalesce();
packet.body->reserve(0, aead.getCipherOverhead());
CHECK_GE(packet.body->tailroom(), aead.getCipherOverhead());
auto body = aead.inplaceEncrypt(
std::move(packet.body), packet.header.get(), packetNum);
body->coalesce();
encryptPacketHeader(
headerForm,
packet.header->writableData(),
packet.header->length(),
body->data(),
body->length(),
headerCipher);
auto packetBuf = std::move(packet.header);
packetBuf->prependChain(std::move(body));
auto packetSize = packetBuf->computeChainDataLength();
if (connection.qLogger) {
connection.qLogger->addPacket(packet.packet, packetSize);
}
VLOG(10) << nodeToString(connection.nodeType)
<< " sent close packetNum=" << packetNum << " in space=" << pnSpace
<< " " << connection;
// Increment the sequence number.
increaseNextPacketNum(connection, pnSpace);
// best effort writing to the socket, ignore any errors.
auto ret = sock.write(connection.peerAddress, packetBuf);
connection.lossState.totalBytesSent += packetSize;
if (ret < 0) {
VLOG(4) << "Error writing connection close " << folly::errnoStr(errno)
<< " " << connection;
} else {
QUIC_STATS(connection.statsCallback, onWrite, ret);
}
}