OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/quic_packet_generator.h" | 5 #include "net/quic/quic_packet_generator.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "net/quic/quic_ack_notifier.h" |
9 #include "net/quic/quic_fec_group.h" | 10 #include "net/quic/quic_fec_group.h" |
10 #include "net/quic/quic_flags.h" | 11 #include "net/quic/quic_flags.h" |
11 #include "net/quic/quic_utils.h" | 12 #include "net/quic/quic_utils.h" |
12 | 13 |
13 using base::StringPiece; | 14 using base::StringPiece; |
14 | 15 |
15 namespace net { | 16 namespace net { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // We want to put some space between a protected packet and the FEC packet to | 20 // We want to put some space between a protected packet and the FEC packet to |
20 // avoid losing them both within the same loss episode. On the other hand, | 21 // avoid losing them both within the same loss episode. On the other hand, |
21 // we expect to be able to recover from any loss in about an RTT. | 22 // we expect to be able to recover from any loss in about an RTT. |
22 // We resolve this tradeoff by sending an FEC packet atmost half an RTT, | 23 // We resolve this tradeoff by sending an FEC packet atmost half an RTT, |
23 // or equivalently, half the max number of in-flight packets, the first | 24 // or equivalently, half the max number of in-flight packets, the first |
24 // protected packet. Since we don't want to delay an FEC packet past half an | 25 // protected packet. Since we don't want to delay an FEC packet past half an |
25 // RTT, we set the max FEC group size to be half the current congestion window. | 26 // RTT, we set the max FEC group size to be half the current congestion window. |
26 const float kMaxPacketsInFlightMultiplierForFecGroupSize = 0.5; | 27 const float kMaxPacketsInFlightMultiplierForFecGroupSize = 0.5; |
| 28 const float kRttMultiplierForFecTimeout = 0.5; |
27 | 29 |
28 } // namespace | 30 } // namespace |
29 | 31 |
30 class QuicAckNotifier; | 32 class QuicAckNotifier; |
31 | 33 |
32 QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id, | 34 QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id, |
33 QuicFramer* framer, | 35 QuicFramer* framer, |
34 QuicRandom* random_generator, | 36 QuicRandom* random_generator, |
35 DelegateInterface* delegate) | 37 DelegateInterface* delegate) |
36 : delegate_(delegate), | 38 : delegate_(delegate), |
37 debug_delegate_(nullptr), | 39 debug_delegate_(nullptr), |
38 packet_creator_(connection_id, framer, random_generator), | 40 packet_creator_(connection_id, framer, random_generator), |
39 batch_mode_(false), | 41 batch_mode_(false), |
| 42 fec_timeout_(QuicTime::Delta::Zero()), |
40 should_fec_protect_(false), | 43 should_fec_protect_(false), |
41 should_send_ack_(false), | 44 should_send_ack_(false), |
42 should_send_feedback_(false), | 45 should_send_feedback_(false), |
43 should_send_stop_waiting_(false) {} | 46 should_send_stop_waiting_(false) { |
| 47 } |
44 | 48 |
45 QuicPacketGenerator::~QuicPacketGenerator() { | 49 QuicPacketGenerator::~QuicPacketGenerator() { |
46 for (QuicFrames::iterator it = queued_control_frames_.begin(); | 50 for (QuicFrames::iterator it = queued_control_frames_.begin(); |
47 it != queued_control_frames_.end(); ++it) { | 51 it != queued_control_frames_.end(); ++it) { |
48 switch (it->type) { | 52 switch (it->type) { |
49 case PADDING_FRAME: | 53 case PADDING_FRAME: |
50 delete it->padding_frame; | 54 delete it->padding_frame; |
51 break; | 55 break; |
52 case STREAM_FRAME: | 56 case STREAM_FRAME: |
53 delete it->stream_frame; | 57 delete it->stream_frame; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 } | 89 } |
86 } | 90 } |
87 | 91 |
88 void QuicPacketGenerator::OnCongestionWindowChange( | 92 void QuicPacketGenerator::OnCongestionWindowChange( |
89 QuicPacketCount max_packets_in_flight) { | 93 QuicPacketCount max_packets_in_flight) { |
90 packet_creator_.set_max_packets_per_fec_group( | 94 packet_creator_.set_max_packets_per_fec_group( |
91 static_cast<size_t>(kMaxPacketsInFlightMultiplierForFecGroupSize * | 95 static_cast<size_t>(kMaxPacketsInFlightMultiplierForFecGroupSize * |
92 max_packets_in_flight)); | 96 max_packets_in_flight)); |
93 } | 97 } |
94 | 98 |
| 99 void QuicPacketGenerator::OnRttChange(QuicTime::Delta rtt) { |
| 100 fec_timeout_ = rtt.Multiply(kRttMultiplierForFecTimeout); |
| 101 } |
| 102 |
95 void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback, | 103 void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback, |
96 bool also_send_stop_waiting) { | 104 bool also_send_stop_waiting) { |
97 if (FLAGS_quic_disallow_multiple_pending_ack_frames) { | 105 if (FLAGS_quic_disallow_multiple_pending_ack_frames) { |
98 if (pending_ack_frame_ != nullptr) { | 106 if (pending_ack_frame_ != nullptr) { |
99 // Ack already queued, nothing to do. | 107 // Ack already queued, nothing to do. |
100 return; | 108 return; |
101 } | 109 } |
102 | 110 |
103 if (also_send_feedback && pending_feedback_frame_ != nullptr) { | 111 if (also_send_feedback && pending_feedback_frame_ != nullptr) { |
104 LOG(DFATAL) << "Should only ever be one pending feedback frame."; | 112 LOG(DFATAL) << "Should only ever be one pending feedback frame."; |
(...skipping 15 matching lines...) Expand all Loading... |
120 void QuicPacketGenerator::SetShouldSendStopWaiting() { | 128 void QuicPacketGenerator::SetShouldSendStopWaiting() { |
121 should_send_stop_waiting_ = true; | 129 should_send_stop_waiting_ = true; |
122 SendQueuedFrames(false); | 130 SendQueuedFrames(false); |
123 } | 131 } |
124 | 132 |
125 void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) { | 133 void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) { |
126 queued_control_frames_.push_back(frame); | 134 queued_control_frames_.push_back(frame); |
127 SendQueuedFrames(false); | 135 SendQueuedFrames(false); |
128 } | 136 } |
129 | 137 |
130 QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, | 138 QuicConsumedData QuicPacketGenerator::ConsumeData( |
131 const IOVector& data_to_write, | 139 QuicStreamId id, |
132 QuicStreamOffset offset, | 140 const IOVector& data_to_write, |
133 bool fin, | 141 QuicStreamOffset offset, |
134 FecProtection fec_protection, | 142 bool fin, |
135 QuicAckNotifier* notifier) { | 143 FecProtection fec_protection, |
| 144 QuicAckNotifier::DelegateInterface* delegate) { |
136 IsHandshake handshake = id == kCryptoStreamId ? IS_HANDSHAKE : NOT_HANDSHAKE; | 145 IsHandshake handshake = id == kCryptoStreamId ? IS_HANDSHAKE : NOT_HANDSHAKE; |
137 // To make reasoning about crypto frames easier, we don't combine them with | 146 // To make reasoning about crypto frames easier, we don't combine them with |
138 // other retransmittable frames in a single packet. | 147 // other retransmittable frames in a single packet. |
139 const bool flush = handshake == IS_HANDSHAKE && | 148 const bool flush = handshake == IS_HANDSHAKE && |
140 packet_creator_.HasPendingRetransmittableFrames(); | 149 packet_creator_.HasPendingRetransmittableFrames(); |
141 SendQueuedFrames(flush); | 150 SendQueuedFrames(flush); |
142 | 151 |
143 size_t total_bytes_consumed = 0; | 152 size_t total_bytes_consumed = 0; |
144 bool fin_consumed = false; | 153 bool fin_consumed = false; |
145 | 154 |
146 if (!packet_creator_.HasRoomForStreamFrame(id, offset)) { | 155 if (!packet_creator_.HasRoomForStreamFrame(id, offset)) { |
147 SerializeAndSendPacket(); | 156 SerializeAndSendPacket(); |
148 } | 157 } |
149 | 158 |
150 if (fec_protection == MUST_FEC_PROTECT) { | 159 if (fec_protection == MUST_FEC_PROTECT) { |
151 MaybeStartFecProtection(); | 160 MaybeStartFecProtection(); |
152 } | 161 } |
153 | 162 |
| 163 // This notifier will be owned by the AckNotifierManager (or deleted below) if |
| 164 // not attached to a packet. |
| 165 QuicAckNotifier* notifier = nullptr; |
| 166 if (delegate != nullptr) { |
| 167 notifier = new QuicAckNotifier(delegate); |
| 168 } |
| 169 |
154 IOVector data = data_to_write; | 170 IOVector data = data_to_write; |
155 size_t data_size = data.TotalBufferSize(); | 171 size_t data_size = data.TotalBufferSize(); |
| 172 if (FLAGS_quic_empty_data_no_fin_early_return && !fin && (data_size == 0)) { |
| 173 LOG(DFATAL) << "Attempt to consume empty data without FIN."; |
| 174 return QuicConsumedData(0, false); |
| 175 } |
| 176 |
| 177 int frames_created = 0; |
156 while (delegate_->ShouldGeneratePacket(NOT_RETRANSMISSION, | 178 while (delegate_->ShouldGeneratePacket(NOT_RETRANSMISSION, |
157 HAS_RETRANSMITTABLE_DATA, handshake)) { | 179 HAS_RETRANSMITTABLE_DATA, handshake)) { |
158 QuicFrame frame; | 180 QuicFrame frame; |
159 size_t bytes_consumed; | 181 size_t bytes_consumed = packet_creator_.CreateStreamFrame( |
160 if (notifier != nullptr) { | 182 id, data, offset + total_bytes_consumed, fin, &frame); |
161 // We want to track which packet this stream frame ends up in. | 183 ++frames_created; |
162 bytes_consumed = packet_creator_.CreateStreamFrameWithNotifier( | 184 |
163 id, data, offset + total_bytes_consumed, fin, notifier, &frame); | 185 // We want to track which packet this stream frame ends up in. |
164 } else { | 186 frame.stream_frame->notifier = notifier; |
165 bytes_consumed = packet_creator_.CreateStreamFrame( | 187 |
166 id, data, offset + total_bytes_consumed, fin, &frame); | |
167 } | |
168 if (!AddFrame(frame)) { | 188 if (!AddFrame(frame)) { |
169 LOG(DFATAL) << "Failed to add stream frame."; | 189 LOG(DFATAL) << "Failed to add stream frame."; |
170 // Inability to add a STREAM frame creates an unrecoverable hole in a | 190 // Inability to add a STREAM frame creates an unrecoverable hole in a |
171 // the stream, so it's best to close the connection. | 191 // the stream, so it's best to close the connection. |
172 delegate_->CloseConnection(QUIC_INTERNAL_ERROR, false); | 192 delegate_->CloseConnection(QUIC_INTERNAL_ERROR, false); |
| 193 delete notifier; |
173 return QuicConsumedData(0, false); | 194 return QuicConsumedData(0, false); |
174 } | 195 } |
175 | 196 |
176 total_bytes_consumed += bytes_consumed; | 197 total_bytes_consumed += bytes_consumed; |
177 fin_consumed = fin && total_bytes_consumed == data_size; | 198 fin_consumed = fin && total_bytes_consumed == data_size; |
178 data.Consume(bytes_consumed); | 199 data.Consume(bytes_consumed); |
179 DCHECK(data.Empty() || packet_creator_.BytesFree() == 0u); | 200 DCHECK(data.Empty() || packet_creator_.BytesFree() == 0u); |
180 | 201 |
181 // TODO(ianswett): Restore packet reordering. | 202 // TODO(ianswett): Restore packet reordering. |
182 if (!InBatchMode() || !packet_creator_.HasRoomForStreamFrame(id, offset)) { | 203 if (!InBatchMode() || !packet_creator_.HasRoomForStreamFrame(id, offset)) { |
183 SerializeAndSendPacket(); | 204 SerializeAndSendPacket(); |
184 } | 205 } |
185 | 206 |
186 if (data.Empty()) { | 207 if (data.Empty()) { |
187 // We're done writing the data. Exit the loop. | 208 // We're done writing the data. Exit the loop. |
188 // We don't make this a precondition because we could have 0 bytes of data | 209 // We don't make this a precondition because we could have 0 bytes of data |
189 // if we're simply writing a fin. | 210 // if we're simply writing a fin. |
190 if (fec_protection == MUST_FEC_PROTECT) { | 211 if (fec_protection == MUST_FEC_PROTECT) { |
191 // Turn off FEC protection when we're done writing protected data. | 212 // Turn off FEC protection when we're done writing protected data. |
192 DVLOG(1) << "Turning FEC protection OFF"; | 213 DVLOG(1) << "Turning FEC protection OFF"; |
193 should_fec_protect_ = false; | 214 should_fec_protect_ = false; |
194 } | 215 } |
195 break; | 216 break; |
196 } | 217 } |
197 } | 218 } |
198 | 219 |
| 220 if (notifier != nullptr && frames_created == 0) { |
| 221 // Safe to delete the AckNotifer as it was never attached to a packet. |
| 222 delete notifier; |
| 223 } |
| 224 |
199 // Don't allow the handshake to be bundled with other retransmittable frames. | 225 // Don't allow the handshake to be bundled with other retransmittable frames. |
200 if (handshake == IS_HANDSHAKE) { | 226 if (handshake == IS_HANDSHAKE) { |
201 SendQueuedFrames(true); | 227 SendQueuedFrames(true); |
202 } | 228 } |
203 | 229 |
204 // Try to close FEC group since we've either run out of data to send or we're | 230 // Try to close FEC group since we've either run out of data to send or we're |
205 // blocked. If not in batch mode, force close the group. | 231 // blocked. If not in batch mode, force close the group. |
206 // TODO(jri): This method should be called with flush=false here | 232 // TODO(jri): This method should be called with flush=false here |
207 // once the timer-based FEC sending is done, to separate FEC sending from | 233 // once the timer-based FEC sending is done, to separate FEC sending from |
208 // the end of batch operations. | 234 // the end of batch operations. |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 packet_creator_.set_connection_id_length(PACKET_8BYTE_CONNECTION_ID); | 445 packet_creator_.set_connection_id_length(PACKET_8BYTE_CONNECTION_ID); |
420 } | 446 } |
421 } | 447 } |
422 | 448 |
423 | 449 |
424 void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) { | 450 void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) { |
425 packet_creator_.set_encryption_level(level); | 451 packet_creator_.set_encryption_level(level); |
426 } | 452 } |
427 | 453 |
428 } // namespace net | 454 } // namespace net |
OLD | NEW |