Index: net/quic/quic_connection.cc |
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc |
index 2651433375e78d6875bae4317a93dc55342a83f7..8c19758ec76df340182d8f890e3ab37f0ff3db72 100644 |
--- a/net/quic/quic_connection.cc |
+++ b/net/quic/quic_connection.cc |
@@ -58,6 +58,21 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { |
return delta <= kMaxPacketGap; |
} |
+QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames) |
+ : frames(unacked_frames), |
+ number_nacks(0) { |
+} |
+ |
+QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames, |
+ std::string data) |
+ : frames(unacked_frames), |
+ number_nacks(0), |
+ data(data) { |
+} |
+ |
+QuicConnection::UnackedPacket::~UnackedPacket() { |
+} |
+ |
QuicConnection::QuicConnection(QuicGuid guid, |
IPEndPoint address, |
QuicConnectionHelperInterface* helper) |
@@ -99,19 +114,53 @@ QuicConnection::QuicConnection(QuicGuid guid, |
} |
QuicConnection::~QuicConnection() { |
- for (UnackedPacketMap::iterator it = unacked_packets_.begin(); |
- it != unacked_packets_.end(); ++it) { |
- delete it->second.packet; |
+ for (UnackedPacketMap::iterator u = unacked_packets_.begin(); |
jar (doing other things)
2013/01/16 23:59:11
nit: avoid single letter variable names. Use of "
Ian Swett
2013/01/17 15:33:27
Agreed, that is a terrible name. I have no idea w
|
+ u != unacked_packets_.end(); ++u) { |
+ DeleteUnackedPacket(u->second); |
} |
+ STLDeleteValues(&unacked_packets_); |
jar (doing other things)
2013/01/16 23:59:11
nit: It seems strange to iterate over the map star
Ian Swett
2013/01/17 15:33:27
I hated writing it. I actually made a destructor,
jar (doing other things)
2013/01/17 16:14:33
+1 That would certainly help IMO.
|
STLDeleteValues(&group_map_); |
- // Queued packets that are not to be resent are owned |
- // by the packet queue. |
for (QueuedPacketList::iterator q = queued_packets_.begin(); |
jar (doing other things)
2013/01/16 23:59:11
nit: "q" should be a better name (...yeah... ya'
Ian Swett
2013/01/17 15:33:27
Done.
|
q != queued_packets_.end(); ++q) { |
- if (!q->resend) delete q->packet; |
+ delete q->packet; |
} |
} |
+void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) { |
+ switch (frame->type) { |
+ case STREAM_FRAME: |
+ delete frame->stream_frame; |
+ break; |
+ case ACK_FRAME: |
+ delete frame->ack_frame; |
+ break; |
+ case CONGESTION_FEEDBACK_FRAME: |
+ delete frame->congestion_feedback_frame; |
+ break; |
+ case RST_STREAM_FRAME: |
+ delete frame->rst_stream_frame; |
+ break; |
+ case CONNECTION_CLOSE_FRAME: |
+ delete frame->connection_close_frame; |
+ break; |
+ case PDU_FRAME: // Fall through. |
+ case NUM_FRAME_TYPES: |
+ DCHECK(false) << "Cannot delete type: " << frame->type; |
+ } |
+} |
+ |
+void QuicConnection::DeleteUnackedPacket(UnackedPacket* unacked) { |
+ for (QuicFrames::iterator it = unacked->frames.begin(); |
+ it != unacked->frames.end(); ++it) { |
+ DCHECK(ShouldResend(*it)); |
+ DeleteEnclosedFrame(&(*it)); |
+ } |
+} |
+ |
+bool QuicConnection::ShouldResend(const QuicFrame& frame) { |
+ return frame.type != ACK_FRAME && frame.type != CONGESTION_FEEDBACK_FRAME; |
+} |
+ |
void QuicConnection::OnError(QuicFramer* framer) { |
SendConnectionClose(framer->error()); |
} |
@@ -270,6 +319,10 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( |
// Packet was acked, so remove it from our unacked packet list. |
DVLOG(1) << "Got an ack for " << it->first; |
// TODO(rch): This is inefficient and should be sped up. |
+ // TODO(ianswett): Ensure this inner loop is applicable now that we're |
+ // always sending packets with new sequence numbers. I believe it may |
+ // only be relevant for the first crypto connect packet, which doesn't |
+ // get a new packet sequence number. |
// The acked packet might be queued (if a resend had been attempted). |
for (QueuedPacketList::iterator q = queued_packets_.begin(); |
q != queued_packets_.end(); ++q) { |
@@ -279,7 +332,8 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( |
} |
} |
acked_packets.insert(it->first); |
- delete it->second.packet; |
+ DeleteUnackedPacket(it->second); |
+ delete it->second; |
UnackedPacketMap::iterator it_tmp = it; |
++it; |
unacked_packets_.erase(it_tmp); |
@@ -298,8 +352,8 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( |
if (it->first < peer_largest_observed_packet_) { |
// The peer got packets after this sequence number. This is an explicit |
// nack. |
- ++(it->second.number_nacks); |
- if (it->second.number_nacks >= kNumberOfNacksBeforeResend && |
+ ++(it->second->number_nacks); |
+ if (it->second->number_nacks >= kNumberOfNacksBeforeResend && |
resent_packets < kMaxResendPerAck) { |
resend_number = it->first; |
} |
@@ -424,8 +478,9 @@ QuicConsumedData QuicConnection::SendStreamData( |
while (queued_packets_.empty()) { |
vector<PacketPair> packets; |
+ QuicFrames frames; |
size_t bytes_consumed = |
- packet_creator_.DataToStream(id, data, offset, fin, &packets); |
+ packet_creator_.DataToStream(id, data, offset, fin, &packets, &frames); |
total_bytes_consumed += bytes_consumed; |
offset += bytes_consumed; |
fin_consumed = fin && bytes_consumed == data.size(); |
@@ -433,14 +488,24 @@ QuicConsumedData QuicConnection::SendStreamData( |
DCHECK_LT(0u, packets.size()); |
for (size_t i = 0; i < packets.size(); ++i) { |
+ // Resend is false for FEC packets. |
+ bool should_resend = !packets[i].second->IsFecPacket(); |
SendPacket(packets[i].first, |
packets[i].second, |
- // Resend is false for FEC packets. |
- !packets[i].second->IsFecPacket(), |
+ should_resend, |
false, |
false); |
- unacked_packets_.insert(make_pair(packets[i].first, |
- UnackedPacket(packets[i].second))); |
+ if (should_resend) { |
+ QuicFrames unacked_frames; |
+ unacked_frames.push_back(frames[i]); |
+ UnackedPacket* unacked = new UnackedPacket( |
+ unacked_frames, frames[i].stream_frame->data.as_string()); |
+ // Ensure the string piece points to the owned copy of the data. |
+ unacked->frames[0].stream_frame->data = StringPiece(unacked->data); |
+ unacked_packets_.insert(make_pair(packets[i].first, unacked)); |
+ } else { |
+ DeleteEnclosedFrame(&frames[i]); |
+ } |
} |
if (last_packet != NULL) { |
@@ -459,13 +524,13 @@ QuicConsumedData QuicConnection::SendStreamData( |
void QuicConnection::SendRstStream(QuicStreamId id, |
QuicErrorCode error, |
QuicStreamOffset offset) { |
- // TODO(ianswett): Queue the frame and use WriteData instead of SendPacket |
- // once we support re-sending frames instead of packets. |
- PacketPair packetpair = packet_creator_.ResetStream(id, offset, error); |
+ queued_control_frames_.push_back(QuicFrame( |
+ new QuicRstStreamFrame(id, offset, error))); |
- SendPacket(packetpair.first, packetpair.second, true, false, false); |
- unacked_packets_.insert(make_pair(packetpair.first, |
- UnackedPacket(packetpair.second))); |
+ // Try to write immediately if possible. |
+ if (CanWrite(false)) { |
+ WriteData(); |
+ } |
} |
void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, |
@@ -506,19 +571,33 @@ bool QuicConnection::OnCanWrite() { |
bool QuicConnection::WriteData() { |
DCHECK_EQ(false, write_blocked_); |
// Serialize the ack and congestion frames before draining the pending queue. |
- QuicFrames frames; |
if (should_send_ack_) { |
- frames.push_back(QuicFrame(&outgoing_ack_)); |
+ queued_control_frames_.push_back(QuicFrame(&outgoing_ack_)); |
} |
if (should_send_congestion_feedback_) { |
- frames.push_back(QuicFrame(&outgoing_congestion_feedback_)); |
+ queued_control_frames_.push_back(QuicFrame(&outgoing_congestion_feedback_)); |
} |
- while (!frames.empty()) { |
+ while (!queued_control_frames_.empty()) { |
size_t num_serialized; |
- PacketPair pair = packet_creator_.SerializeFrames(frames, &num_serialized); |
+ PacketPair pair = packet_creator_.SerializeFrames( |
+ queued_control_frames_, &num_serialized); |
+ // If any serialized frames need to be resent, add them to unacked_packets. |
+ QuicFrames unacked_frames; |
+ for (QuicFrames::const_iterator iter = queued_control_frames_.begin(); |
+ iter != queued_control_frames_.begin() + num_serialized; ++iter) { |
+ if (ShouldResend(*iter)) { |
+ unacked_frames.push_back(*iter); |
+ } |
+ } |
+ if (!unacked_frames.empty()) { |
+ unacked_packets_.insert(make_pair(pair.first, |
+ new UnackedPacket(unacked_frames))); |
+ } |
queued_packets_.push_back(QueuedPacket( |
- pair.first, pair.second, false, false)); |
- frames.erase(frames.begin(), frames.begin() + num_serialized); |
+ pair.first, pair.second, !unacked_frames.empty(), false)); |
+ queued_control_frames_.erase( |
+ queued_control_frames_.begin(), |
+ queued_control_frames_.begin() + num_serialized); |
} |
should_send_ack_ = false; |
should_send_congestion_feedback_ = false; |
@@ -566,22 +645,20 @@ void QuicConnection::MaybeResendPacket( |
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
if (it != unacked_packets_.end()) { |
- QuicPacket* packet = it->second.packet; |
+ UnackedPacket* unacked = it->second; |
+ // TODO(ianswett): Never change the sequence number of the connect packet. |
unacked_packets_.erase(it); |
- // Re-frame the packet with a new sequence number for resend. |
- QuicPacketSequenceNumber new_sequence_number = |
- packet_creator_.SetNewSequenceNumber(packet); |
+ // Re-packetize the frames with a new sequence number for resend. |
+ // Resent data packets do not use FEC, even when it's enabled. |
+ PacketPair packetpair = packet_creator_.SerializeAllFrames(unacked->frames); |
DVLOG(1) << "Resending unacked packet " << sequence_number << " as " |
- << new_sequence_number; |
- // Clear the FEC group. |
- framer_.WriteFecGroup(0u, packet); |
- unacked_packets_.insert(make_pair(new_sequence_number, |
- UnackedPacket(packet))); |
+ << packetpair.first; |
+ unacked_packets_.insert(make_pair(packetpair.first, unacked)); |
// Make sure if this was our least unacked packet, that we update our |
// outgoing ack. If this wasn't the least unacked, this is a no-op. |
UpdateLeastUnacked(sequence_number); |
- SendPacket(new_sequence_number, packet, true, false, true); |
+ SendPacket(packetpair.first, packetpair.second, true, false, true); |
} else { |
DVLOG(2) << "alarm fired for " << sequence_number |
<< " but it has been acked"; |
@@ -658,7 +735,7 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number, |
DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds(); |
scheduler_->SentPacket(sequence_number, packet->length(), is_retransmit); |
- if (!should_resend) delete packet; |
+ delete packet; |
return true; |
} |