summaryrefslogtreecommitdiff
path: root/chromium/net/quic/quic_packet_creator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/quic_packet_creator.cc')
-rw-r--r--chromium/net/quic/quic_packet_creator.cc223
1 files changed, 158 insertions, 65 deletions
diff --git a/chromium/net/quic/quic_packet_creator.cc b/chromium/net/quic/quic_packet_creator.cc
index 609ebcbd734..cb37cc271de 100644
--- a/chromium/net/quic/quic_packet_creator.cc
+++ b/chromium/net/quic/quic_packet_creator.cc
@@ -19,13 +19,48 @@ using std::vector;
namespace net {
+// A QuicRandom wrapper that gets a bucket of entropy and distributes it
+// bit-by-bit. Replenishes the bucket as needed. Not thread-safe. Expose this
+// class if single bit randomness is needed elsewhere.
+class QuicRandomBoolSource {
+ public:
+ // random: Source of entropy. Not owned.
+ explicit QuicRandomBoolSource(QuicRandom* random)
+ : random_(random),
+ bit_bucket_(0),
+ bit_mask_(0) {}
+
+ ~QuicRandomBoolSource() {}
+
+ // Returns the next random bit from the bucket.
+ bool RandBool() {
+ if (bit_mask_ == 0) {
+ bit_bucket_ = random_->RandUint64();
+ bit_mask_ = 1;
+ }
+ bool result = ((bit_bucket_ & bit_mask_) != 0);
+ bit_mask_ <<= 1;
+ return result;
+ }
+
+ private:
+ // Source of entropy.
+ QuicRandom* random_;
+ // Stored random bits.
+ uint64 bit_bucket_;
+ // The next available bit has "1" in the mask. Zero means empty bucket.
+ uint64 bit_mask_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicRandomBoolSource);
+};
+
QuicPacketCreator::QuicPacketCreator(QuicGuid guid,
QuicFramer* framer,
QuicRandom* random_generator,
bool is_server)
: guid_(guid),
framer_(framer),
- random_generator_(random_generator),
+ random_bool_source_(new QuicRandomBoolSource(random_generator)),
sequence_number_(0),
fec_group_number_(0),
is_server_(is_server),
@@ -41,6 +76,7 @@ QuicPacketCreator::~QuicPacketCreator() {
void QuicPacketCreator::OnBuiltFecProtectedPayload(
const QuicPacketHeader& header, StringPiece payload) {
if (fec_group_.get()) {
+ DCHECK_NE(0u, header.fec_group);
fec_group_->Update(header, payload);
}
}
@@ -85,15 +121,8 @@ void QuicPacketCreator::UpdateSequenceNumberLength(
bytes_per_second / options_.max_packet_length;
const uint64 delta = max(current_delta, congestion_window);
- if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- options_.send_sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
- } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- options_.send_sequence_number_length = PACKET_2BYTE_SEQUENCE_NUMBER;
- } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) {
- options_.send_sequence_number_length = PACKET_4BYTE_SEQUENCE_NUMBER;
- } else {
- options_.send_sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER;
- }
+ options_.send_sequence_number_length =
+ QuicFramer::GetMinSequenceNumberLength(delta * 4);
}
bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
@@ -116,7 +145,7 @@ size_t QuicPacketCreator::StreamFramePacketOverhead(
}
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
- StringPiece data,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
QuicFrame* frame) {
@@ -131,47 +160,53 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
framer_->version(), id, offset, true);
}
- const size_t free_bytes = BytesFree();
- size_t bytes_consumed = 0;
-
- if (data.size() != 0) {
- // When a STREAM frame is the last frame in a packet, it consumes two fewer
- // bytes of framing overhead.
- // Anytime more data is available than fits in with the extra two bytes,
- // the frame will be the last, and up to two extra bytes are consumed.
- // TODO(ianswett): If QUIC pads, the 1 byte PADDING frame does not fit when
- // 1 byte is available, because then the STREAM frame isn't the last.
-
- // The minimum frame size(0 bytes of data) if it's not the last frame.
- size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
- framer_->version(), id, offset, false);
- // Check if it's the last frame in the packet.
- if (data.size() + min_frame_size > free_bytes) {
- // The minimum frame size(0 bytes of data) if it is the last frame.
- size_t min_last_frame_size = QuicFramer::GetMinStreamFrameSize(
- framer_->version(), id, offset, true);
- bytes_consumed =
- min<size_t>(free_bytes - min_last_frame_size, data.size());
- } else {
- DCHECK_LT(data.size(), BytesFree());
- bytes_consumed = data.size();
+ if (data.Empty()) {
+ if (!fin) {
+ LOG(DFATAL) << "Creating a stream frame with no data or fin.";
}
+ // Create a new packet for the fin, if necessary.
+ *frame = QuicFrame(new QuicStreamFrame(id, true, offset, data));
+ return 0;
+ }
- bool set_fin = fin && bytes_consumed == data.size(); // Last frame.
- StringPiece data_frame(data.data(), bytes_consumed);
- *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, data_frame));
+ const size_t free_bytes = BytesFree();
+ size_t bytes_consumed = 0;
+ const size_t data_size = data.TotalBufferSize();
+
+ // When a STREAM frame is the last frame in a packet, it consumes two fewer
+ // bytes of framing overhead.
+ // Anytime more data is available than fits in with the extra two bytes,
+ // the frame will be the last, and up to two extra bytes are consumed.
+ // TODO(ianswett): If QUIC pads, the 1 byte PADDING frame does not fit when
+ // 1 byte is available, because then the STREAM frame isn't the last.
+
+ // The minimum frame size(0 bytes of data) if it's not the last frame.
+ size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
+ framer_->version(), id, offset, false);
+ // Check if it's the last frame in the packet.
+ if (data_size + min_frame_size > free_bytes) {
+ // The minimum frame size(0 bytes of data) if it is the last frame.
+ size_t min_last_frame_size = QuicFramer::GetMinStreamFrameSize(
+ framer_->version(), id, offset, true);
+ bytes_consumed =
+ min<size_t>(free_bytes - min_last_frame_size, data_size);
} else {
- DCHECK(fin);
- // Create a new packet for the fin, if necessary.
- *frame = QuicFrame(new QuicStreamFrame(id, true, offset, ""));
+ DCHECK_LT(data_size, BytesFree());
+ bytes_consumed = data_size;
}
+ bool set_fin = fin && bytes_consumed == data_size; // Last frame.
+ IOVector frame_data;
+ frame_data.AppendIovecAtMostBytes(data.iovec(), data.Size(),
+ bytes_consumed);
+ DCHECK_EQ(frame_data.TotalBufferSize(), bytes_consumed);
+ *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, frame_data));
return bytes_consumed;
}
size_t QuicPacketCreator::CreateStreamFrameWithNotifier(
QuicStreamId id,
- StringPiece data,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
QuicAckNotifier* notifier,
@@ -189,18 +224,26 @@ size_t QuicPacketCreator::CreateStreamFrameWithNotifier(
SerializedPacket QuicPacketCreator::ReserializeAllFrames(
const QuicFrames& frames,
QuicSequenceNumberLength original_length) {
- // Temporarily set the sequence number length and disable FEC.
const QuicSequenceNumberLength start_length = sequence_number_length_;
const QuicSequenceNumberLength start_options_length =
options_.send_sequence_number_length;
const QuicFecGroupNumber start_fec_group = fec_group_number_;
+ const size_t start_max_packets_per_fec_group =
+ options_.max_packets_per_fec_group;
+
+ // Temporarily set the sequence number length and disable FEC.
sequence_number_length_ = original_length;
options_.send_sequence_number_length = original_length;
fec_group_number_ = 0;
+ options_.max_packets_per_fec_group = 0;
+
+ // Serialize the packet and restore the fec and sequence number length state.
SerializedPacket serialized_packet = SerializeAllFrames(frames);
sequence_number_length_ = start_length;
options_.send_sequence_number_length = start_options_length;
fec_group_number_ = start_fec_group;
+ options_.max_packets_per_fec_group = start_max_packets_per_fec_group;
+
return serialized_packet;
}
@@ -229,10 +272,20 @@ bool QuicPacketCreator::HasPendingFrames() {
size_t QuicPacketCreator::BytesFree() const {
const size_t max_plaintext_size =
framer_->GetMaxPlaintextSize(options_.max_packet_length);
- if (PacketSize() >= max_plaintext_size) {
+ DCHECK_GE(max_plaintext_size, PacketSize());
+
+ // If the last frame in the packet is a stream frame, then it can be
+ // two bytes smaller than if it were not the last. So this means that
+ // there are two fewer bytes available to the next frame in this case.
+ bool has_trailing_stream_frame =
+ !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME;
+ size_t expanded_packet_size = PacketSize() +
+ (has_trailing_stream_frame ? kQuicStreamPayloadLengthSize : 0);
+
+ if (expanded_packet_size >= max_plaintext_size) {
return 0;
}
- return max_plaintext_size - PacketSize();
+ return max_plaintext_size - expanded_packet_size;
}
size_t QuicPacketCreator::PacketSize() const {
@@ -246,7 +299,7 @@ size_t QuicPacketCreator::PacketSize() const {
packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
send_version_in_packet_,
sequence_number_length_,
- fec_group_number_ == 0 ?
+ options_.max_packets_per_fec_group == 0 ?
NOT_IN_FEC_GROUP : IN_FEC_GROUP);
}
return packet_size_;
@@ -263,18 +316,29 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
QuicPacketHeader header;
FillPacketHeader(fec_group_number_, false, false, &header);
+ MaybeAddPadding();
+
+ size_t max_plaintext_size =
+ framer_->GetMaxPlaintextSize(options_.max_packet_length);
+ DCHECK_GE(max_plaintext_size, packet_size_);
+ // ACK and CONNECTION_CLOSE Frames will be truncated only if they're
+ // the first frame in the packet. If truncation is to occur, then
+ // GetSerializedFrameLength will have returned all bytes free.
+ bool possibly_truncated =
+ packet_size_ != max_plaintext_size ||
+ queued_frames_.size() != 1 ||
+ (queued_frames_.back().type == ACK_FRAME ||
+ queued_frames_.back().type == CONNECTION_CLOSE_FRAME);
SerializedPacket serialized =
framer_->BuildDataPacket(header, queued_frames_, packet_size_);
-
- // Run through all the included frames and if any of them have an AckNotifier
- // registered, then inform the AckNotifier that it should be interested in
- // this packet's sequence number.
- for (QuicFrames::iterator it = queued_frames_.begin();
- it != queued_frames_.end(); ++it) {
- if (it->type == STREAM_FRAME && it->stream_frame->notifier != NULL) {
- it->stream_frame->notifier->AddSequenceNumber(serialized.sequence_number);
- }
+ if (!serialized.packet) {
+ LOG(DFATAL) << "Failed to serialize " << queued_frames_.size()
+ << " frames.";
}
+ // Because of possible truncation, we can't be confident that our
+ // packet size calculation worked correctly.
+ if (!possibly_truncated)
+ DCHECK_EQ(packet_size_, serialized.packet->length());
packet_size_ = 0;
queued_frames_.clear();
@@ -295,7 +359,10 @@ SerializedPacket QuicPacketCreator::SerializeFec() {
fec_group_.reset(NULL);
fec_group_number_ = 0;
packet_size_ = 0;
- DCHECK(serialized.packet);
+ if (!serialized.packet) {
+ LOG(DFATAL) << "Failed to serialize fec packet for group:"
+ << fec_data.fec_group;
+ }
DCHECK_GE(options_.max_packet_length, serialized.packet->length());
return serialized;
}
@@ -334,17 +401,12 @@ void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
header->public_header.sequence_number_length = sequence_number_length_;
bool entropy_flag;
- if (header->packet_sequence_number == 1) {
- DCHECK(!fec_flag);
- // TODO(satyamshekhar): No entropy in the first message.
- // For crypto tests to pass. Fix this by using deterministic QuicRandom.
- entropy_flag = 0;
- } else if (fec_flag) {
+ if (fec_flag) {
// FEC packets don't have an entropy of their own. Entropy flag for FEC
// packets is the XOR of entropy of previous packets.
entropy_flag = fec_entropy_flag;
} else {
- entropy_flag = random_generator_->RandBool();
+ entropy_flag = random_bool_source_->RandBool();
}
header->entropy_flag = entropy_flag;
header->is_in_fec_group = fec_group == 0 ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
@@ -359,13 +421,19 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
bool save_retransmittable_frames) {
size_t frame_len = framer_->GetSerializedFrameLength(
- frame, BytesFree(), queued_frames_.empty());
+ frame, BytesFree(), queued_frames_.empty(), true,
+ options()->send_sequence_number_length);
if (frame_len == 0) {
return false;
}
DCHECK_LT(0u, packet_size_);
+ MaybeStartFEC();
packet_size_ += frame_len;
-
+ // If the last frame in the packet was a stream frame, then once we add the
+ // new frame it's serialization will be two bytes larger.
+ if (!queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME) {
+ packet_size_ += kQuicStreamPayloadLengthSize;
+ }
if (save_retransmittable_frames && ShouldRetransmit(frame)) {
if (queued_retransmittable_frames_.get() == NULL) {
queued_retransmittable_frames_.reset(new RetransmittableFrames());
@@ -383,4 +451,29 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
return true;
}
+void QuicPacketCreator::MaybeAddPadding() {
+ if (BytesFree() == 0) {
+ // Don't pad full packets.
+ return;
+ }
+
+ // If any of the frames in the current packet are on the crypto stream
+ // then they contain handshake messagses, and we should pad them.
+ bool is_handshake = false;
+ for (size_t i = 0; i < queued_frames_.size(); ++i) {
+ if (queued_frames_[i].type == STREAM_FRAME &&
+ queued_frames_[i].stream_frame->stream_id == kCryptoStreamId) {
+ is_handshake = true;
+ break;
+ }
+ }
+ if (!is_handshake) {
+ return;
+ }
+
+ QuicPaddingFrame padding;
+ bool success = AddFrame(QuicFrame(&padding), false);
+ DCHECK(success);
+}
+
} // namespace net