Loading src/quic.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -2937,6 +2937,52 @@ void quic::processRetryPacket(const uint8_t* data, size_t len) { applyHeaderProtection(packet, EncryptionLevel::Initial, _initial_keys.send); buffer send_buf(reinterpret_cast<const char*>(packet.data()), packet.size()); udp::sendData(send_buf, 0); // This server requires a Retry round trip (accept()'s always-Retry // policy for a token-less first Initial), which just changed our DCID — // any 0-RTT packets already sent under the old DCID are now // unreachable and would otherwise just sit in _sent_packets waiting on // their PTO timer, which retransmits only the single oldest unacked // packet at a time and backs off exponentially on each subsequent // firing (checkLossAndRetransmit()) — recovering a handful of early // packets one at a time that way could take multiple seconds. Resend // them all immediately instead, right alongside the retried Initial: // this is what actually makes offering 0-RTT worthwhile against a // server whose default policy always Retries an unrecognized client. if (!_sent_packets.empty()) { std::vector<SentPacket> early_resend; for (auto it = _sent_packets.begin(); it != _sent_packets.end(); ) { if (it->second.sent_as_early_data) { early_resend.push_back(std::move(it->second)); it = _sent_packets.erase(it); } else { ++it; } } for (auto& sp : early_resend) { uint8_t frame_type = 0x08 | 0x02; // STREAM, LEN bit if (sp.stream_offset > 0) frame_type |= 0x04; // OFF bit if (sp.fin) frame_type |= 0x01; std::vector<uint8_t> frame; frame.reserve(1 + 8 + 8 + 8 + sp.data_length); frame.push_back(frame_type); uint8_t vb[8]; size_t vl; vl = encodeVarInt(sp.stream_id, vb); frame.insert(frame.end(), vb, vb + vl); if (sp.stream_offset > 0) { vl = encodeVarInt(sp.stream_offset, vb); frame.insert(frame.end(), vb, vb + vl); } vl = encodeVarInt(sp.data_length, vb); frame.insert(frame.end(), vb, vb + vl); frame.insert(frame.end(), sp.stream_data.begin(), sp.stream_data.end()); uint64_t new_pn = _app_pn_send; std::vector<uint8_t> early_packet = buildZeroRTTPacket(frame); applyHeaderProtection(early_packet, EncryptionLevel::EarlyData, _early_keys.send); sendPacket(early_packet.data(), early_packet.size()); recordSentPacket(new_pn, sp.stream_id, sp.stream_offset, sp.stream_data.data(), sp.stream_data.size(), sp.fin, early_packet.size(), /*sent_as_early_data=*/true); } } } void quic::processShortHeaderPacket(const uint8_t* data, size_t len) { Loading Loading
src/quic.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -2937,6 +2937,52 @@ void quic::processRetryPacket(const uint8_t* data, size_t len) { applyHeaderProtection(packet, EncryptionLevel::Initial, _initial_keys.send); buffer send_buf(reinterpret_cast<const char*>(packet.data()), packet.size()); udp::sendData(send_buf, 0); // This server requires a Retry round trip (accept()'s always-Retry // policy for a token-less first Initial), which just changed our DCID — // any 0-RTT packets already sent under the old DCID are now // unreachable and would otherwise just sit in _sent_packets waiting on // their PTO timer, which retransmits only the single oldest unacked // packet at a time and backs off exponentially on each subsequent // firing (checkLossAndRetransmit()) — recovering a handful of early // packets one at a time that way could take multiple seconds. Resend // them all immediately instead, right alongside the retried Initial: // this is what actually makes offering 0-RTT worthwhile against a // server whose default policy always Retries an unrecognized client. if (!_sent_packets.empty()) { std::vector<SentPacket> early_resend; for (auto it = _sent_packets.begin(); it != _sent_packets.end(); ) { if (it->second.sent_as_early_data) { early_resend.push_back(std::move(it->second)); it = _sent_packets.erase(it); } else { ++it; } } for (auto& sp : early_resend) { uint8_t frame_type = 0x08 | 0x02; // STREAM, LEN bit if (sp.stream_offset > 0) frame_type |= 0x04; // OFF bit if (sp.fin) frame_type |= 0x01; std::vector<uint8_t> frame; frame.reserve(1 + 8 + 8 + 8 + sp.data_length); frame.push_back(frame_type); uint8_t vb[8]; size_t vl; vl = encodeVarInt(sp.stream_id, vb); frame.insert(frame.end(), vb, vb + vl); if (sp.stream_offset > 0) { vl = encodeVarInt(sp.stream_offset, vb); frame.insert(frame.end(), vb, vb + vl); } vl = encodeVarInt(sp.data_length, vb); frame.insert(frame.end(), vb, vb + vl); frame.insert(frame.end(), sp.stream_data.begin(), sp.stream_data.end()); uint64_t new_pn = _app_pn_send; std::vector<uint8_t> early_packet = buildZeroRTTPacket(frame); applyHeaderProtection(early_packet, EncryptionLevel::EarlyData, _early_keys.send); sendPacket(early_packet.data(), early_packet.size()); recordSentPacket(new_pn, sp.stream_id, sp.stream_offset, sp.stream_data.data(), sp.stream_data.size(), sp.fin, early_packet.size(), /*sent_as_early_data=*/true); } } } void quic::processShortHeaderPacket(const uint8_t* data, size_t len) { Loading