| Index: net/quic/quic_packet_generator.cc
|
| diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
|
| index a7f0af08ade11a8577f4d79ce4ca5ddd1f1f281e..22bf530d1949058e1c0f536f7177b92ce7a9f711 100644
|
| --- a/net/quic/quic_packet_generator.cc
|
| +++ b/net/quic/quic_packet_generator.cc
|
| @@ -18,15 +18,19 @@ namespace net {
|
| namespace {
|
|
|
| // We want to put some space between a protected packet and the FEC packet to
|
| -// avoid losing them both within the same loss episode. On the other hand,
|
| -// we expect to be able to recover from any loss in about an RTT.
|
| -// We resolve this tradeoff by sending an FEC packet atmost half an RTT,
|
| -// or equivalently, half the max number of in-flight packets, the first
|
| -// protected packet. Since we don't want to delay an FEC packet past half an
|
| -// RTT, we set the max FEC group size to be half the current congestion window.
|
| +// avoid losing them both within the same loss episode. On the other hand, we
|
| +// expect to be able to recover from any loss in about an RTT. We resolve this
|
| +// tradeoff by sending an FEC packet atmost half an RTT, or equivalently, half
|
| +// the max number of in-flight packets, the first protected packet. Since we
|
| +// don't want to delay an FEC packet past half an RTT, we set the max FEC group
|
| +// size to be half the current congestion window.
|
| const float kMaxPacketsInFlightMultiplierForFecGroupSize = 0.5;
|
| const float kRttMultiplierForFecTimeout = 0.5;
|
|
|
| +// Minimum timeout for FEC alarm, set to half the minimum Tail Loss Probe
|
| +// timeout of 10ms.
|
| +const int64 kMinFecTimeoutMs = 5u;
|
| +
|
| } // namespace
|
|
|
| class QuicAckNotifier;
|
| @@ -42,7 +46,6 @@ QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id,
|
| fec_timeout_(QuicTime::Delta::Zero()),
|
| should_fec_protect_(false),
|
| should_send_ack_(false),
|
| - should_send_feedback_(false),
|
| should_send_stop_waiting_(false) {
|
| }
|
|
|
| @@ -59,9 +62,6 @@ QuicPacketGenerator::~QuicPacketGenerator() {
|
| case ACK_FRAME:
|
| delete it->ack_frame;
|
| break;
|
| - case CONGESTION_FEEDBACK_FRAME:
|
| - delete it->congestion_feedback_frame;
|
| - break;
|
| case RST_STREAM_FRAME:
|
| delete it->rst_stream_frame;
|
| break;
|
| @@ -100,27 +100,18 @@ void QuicPacketGenerator::OnRttChange(QuicTime::Delta rtt) {
|
| fec_timeout_ = rtt.Multiply(kRttMultiplierForFecTimeout);
|
| }
|
|
|
| -void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback,
|
| - bool also_send_stop_waiting) {
|
| - if (FLAGS_quic_disallow_multiple_pending_ack_frames) {
|
| - if (pending_ack_frame_ != nullptr) {
|
| - // Ack already queued, nothing to do.
|
| - return;
|
| - }
|
| -
|
| - if (also_send_feedback && pending_feedback_frame_ != nullptr) {
|
| - LOG(DFATAL) << "Should only ever be one pending feedback frame.";
|
| - return;
|
| - }
|
| +void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) {
|
| + if (pending_ack_frame_ != nullptr) {
|
| + // Ack already queued, nothing to do.
|
| + return;
|
| + }
|
|
|
| - if (also_send_stop_waiting && pending_stop_waiting_frame_ != nullptr) {
|
| - LOG(DFATAL) << "Should only ever be one pending stop waiting frame.";
|
| - return;
|
| - }
|
| + if (also_send_stop_waiting && pending_stop_waiting_frame_ != nullptr) {
|
| + LOG(DFATAL) << "Should only ever be one pending stop waiting frame.";
|
| + return;
|
| }
|
|
|
| should_send_ack_ = true;
|
| - should_send_feedback_ = also_send_feedback;
|
| should_send_stop_waiting_ = also_send_stop_waiting;
|
| SendQueuedFrames(false);
|
| }
|
| @@ -142,11 +133,11 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
|
| bool fin,
|
| FecProtection fec_protection,
|
| QuicAckNotifier::DelegateInterface* delegate) {
|
| - IsHandshake handshake = id == kCryptoStreamId ? IS_HANDSHAKE : NOT_HANDSHAKE;
|
| + bool has_handshake = id == kCryptoStreamId;
|
| // To make reasoning about crypto frames easier, we don't combine them with
|
| // other retransmittable frames in a single packet.
|
| - const bool flush = handshake == IS_HANDSHAKE &&
|
| - packet_creator_.HasPendingRetransmittableFrames();
|
| + const bool flush =
|
| + has_handshake && packet_creator_.HasPendingRetransmittableFrames();
|
| SendQueuedFrames(flush);
|
|
|
| size_t total_bytes_consumed = 0;
|
| @@ -169,14 +160,15 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
|
|
|
| IOVector data = data_to_write;
|
| size_t data_size = data.TotalBufferSize();
|
| - if (FLAGS_quic_empty_data_no_fin_early_return && !fin && (data_size == 0)) {
|
| + if (!fin && (data_size == 0)) {
|
| LOG(DFATAL) << "Attempt to consume empty data without FIN.";
|
| return QuicConsumedData(0, false);
|
| }
|
|
|
| int frames_created = 0;
|
| - while (delegate_->ShouldGeneratePacket(NOT_RETRANSMISSION,
|
| - HAS_RETRANSMITTABLE_DATA, handshake)) {
|
| + while (delegate_->ShouldGeneratePacket(
|
| + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
|
| + has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
|
| QuicFrame frame;
|
| size_t bytes_consumed = packet_creator_.CreateStreamFrame(
|
| id, data, offset + total_bytes_consumed, fin, &frame);
|
| @@ -229,16 +221,13 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
|
| }
|
|
|
| // Don't allow the handshake to be bundled with other retransmittable frames.
|
| - if (handshake == IS_HANDSHAKE) {
|
| + if (has_handshake) {
|
| SendQueuedFrames(true);
|
| }
|
|
|
| // Try to close FEC group since we've either run out of data to send or we're
|
| // blocked. If not in batch mode, force close the group.
|
| - // TODO(jri): This method should be called with flush=false here
|
| - // once the timer-based FEC sending is done, to separate FEC sending from
|
| - // the end of batch operations.
|
| - MaybeSendFecPacketAndCloseGroup(!InBatchMode());
|
| + MaybeSendFecPacketAndCloseGroup(/*flush=*/false);
|
|
|
| DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames());
|
| return QuicConsumedData(total_bytes_consumed, fin_consumed);
|
| @@ -247,8 +236,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(
|
| bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
|
| DCHECK(HasPendingFrames());
|
| HasRetransmittableData retransmittable =
|
| - (should_send_ack_ || should_send_feedback_ || should_send_stop_waiting_)
|
| - ? NO_RETRANSMITTABLE_DATA : HAS_RETRANSMITTABLE_DATA;
|
| + (should_send_ack_ || should_send_stop_waiting_)
|
| + ? NO_RETRANSMITTABLE_DATA
|
| + : HAS_RETRANSMITTABLE_DATA;
|
| if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
|
| DCHECK(!queued_control_frames_.empty()); // These are retransmittable.
|
| }
|
| @@ -265,15 +255,10 @@ void QuicPacketGenerator::SendQueuedFrames(bool flush) {
|
| SerializeAndSendPacket();
|
| }
|
| }
|
| -
|
| - if (!InBatchMode() || flush) {
|
| - if (packet_creator_.HasPendingFrames()) {
|
| - SerializeAndSendPacket();
|
| - }
|
| - // Ensure the FEC group is closed at the end of this method unless other
|
| - // writes are pending.
|
| - MaybeSendFecPacketAndCloseGroup(true);
|
| + if (packet_creator_.HasPendingFrames() && (flush || !InBatchMode())) {
|
| + SerializeAndSendPacket();
|
| }
|
| + MaybeSendFecPacketAndCloseGroup(flush);
|
| }
|
|
|
| void QuicPacketGenerator::MaybeStartFecProtection() {
|
| @@ -299,9 +284,7 @@ void QuicPacketGenerator::MaybeStartFecProtection() {
|
| }
|
|
|
| void QuicPacketGenerator::MaybeSendFecPacketAndCloseGroup(bool force) {
|
| - if (!packet_creator_.IsFecProtected() ||
|
| - packet_creator_.HasPendingFrames() ||
|
| - !packet_creator_.ShouldSendFec(force)) {
|
| + if (!ShouldSendFecPacket(force)) {
|
| return;
|
| }
|
| // TODO(jri): SerializeFec can return a NULL packet, and this should
|
| @@ -319,6 +302,36 @@ void QuicPacketGenerator::MaybeSendFecPacketAndCloseGroup(bool force) {
|
| }
|
| }
|
|
|
| +bool QuicPacketGenerator::ShouldSendFecPacket(bool force) {
|
| + return packet_creator_.IsFecProtected() &&
|
| + !packet_creator_.HasPendingFrames() &&
|
| + packet_creator_.ShouldSendFec(force);
|
| +}
|
| +
|
| +void QuicPacketGenerator::OnFecTimeout() {
|
| + DCHECK(!InBatchMode());
|
| + if (!ShouldSendFecPacket(true)) {
|
| + LOG(DFATAL) << "No FEC packet to send on FEC timeout.";
|
| + return;
|
| + }
|
| + // Flush out any pending frames in the generator and the creator, and then
|
| + // send out FEC packet.
|
| + SendQueuedFrames(true);
|
| + MaybeSendFecPacketAndCloseGroup(/*flush=*/true);
|
| +}
|
| +
|
| +QuicTime::Delta QuicPacketGenerator::GetFecTimeout(
|
| + QuicPacketSequenceNumber sequence_number) {
|
| + // Do not set up FEC alarm for |sequence_number| it is not the first packet in
|
| + // the current group.
|
| + if (packet_creator_.IsFecGroupOpen() &&
|
| + (sequence_number == packet_creator_.fec_group_number())) {
|
| + return QuicTime::Delta::Max(
|
| + fec_timeout_, QuicTime::Delta::FromMilliseconds(kMinFecTimeoutMs));
|
| + }
|
| + return QuicTime::Delta::Infinite();
|
| +}
|
| +
|
| bool QuicPacketGenerator::InBatchMode() {
|
| return batch_mode_;
|
| }
|
| @@ -341,8 +354,8 @@ bool QuicPacketGenerator::HasQueuedFrames() const {
|
| }
|
|
|
| bool QuicPacketGenerator::HasPendingFrames() const {
|
| - return should_send_ack_ || should_send_feedback_ ||
|
| - should_send_stop_waiting_ || !queued_control_frames_.empty();
|
| + return should_send_ack_ || should_send_stop_waiting_ ||
|
| + !queued_control_frames_.empty();
|
| }
|
|
|
| bool QuicPacketGenerator::AddNextPendingFrame() {
|
| @@ -355,15 +368,6 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
|
| return !should_send_ack_;
|
| }
|
|
|
| - if (should_send_feedback_) {
|
| - pending_feedback_frame_.reset(delegate_->CreateFeedbackFrame());
|
| - // If we can't this add the frame now, then we still need to do so later.
|
| - should_send_feedback_ = !AddFrame(QuicFrame(pending_feedback_frame_.get()));
|
| - // Return success if we have cleared out this flag (i.e., added the frame).
|
| - // If we still need to send, then the frame is full, and we have failed.
|
| - return !should_send_feedback_;
|
| - }
|
| -
|
| if (should_send_stop_waiting_) {
|
| pending_stop_waiting_frame_.reset(delegate_->CreateStopWaitingFrame());
|
| // If we can't this add the frame now, then we still need to do so later.
|
| @@ -403,14 +407,11 @@ void QuicPacketGenerator::SerializeAndSendPacket() {
|
| }
|
|
|
| delegate_->OnSerializedPacket(serialized_packet);
|
| - MaybeSendFecPacketAndCloseGroup(false);
|
| + MaybeSendFecPacketAndCloseGroup(/*flush=*/false);
|
|
|
| // The packet has now been serialized, safe to delete pending frames.
|
| - if (FLAGS_quic_disallow_multiple_pending_ack_frames) {
|
| - pending_ack_frame_.reset();
|
| - pending_feedback_frame_.reset();
|
| - pending_stop_waiting_frame_.reset();
|
| - }
|
| + pending_ack_frame_.reset();
|
| + pending_stop_waiting_frame_.reset();
|
| }
|
|
|
| void QuicPacketGenerator::StopSendingVersion() {
|
|
|