blob: 95642bd941ea63c58517a16ebba0c8e960535975 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_packet_creator.h"
#include "base/logging.h"
#include "net/quic/quic_utils.h"
using base::StringPiece;
using std::make_pair;
using std::min;
using std::pair;
using std::vector;
namespace net {
QuicPacketCreator::QuicPacketCreator(QuicGuid guid, QuicFramer* framer)
: guid_(guid),
framer_(framer),
sequence_number_(0),
fec_group_number_(1) {
framer_->set_fec_builder(this);
}
QuicPacketCreator::~QuicPacketCreator() {
}
void QuicPacketCreator::OnBuiltFecProtectedPayload(
const QuicPacketHeader& header,
StringPiece payload) {
if (fec_group_.get()) {
fec_group_->Update(header, payload);
}
}
size_t QuicPacketCreator::DataToStream(QuicStreamId id,
StringPiece data,
QuicStreamOffset offset,
bool fin,
vector<PacketPair>* packets) {
DCHECK_GT(options_.max_packet_length,
QuicUtils::StreamFramePacketOverhead(1));
DCHECK_LT(0u, options_.max_num_packets);
QuicPacketHeader header;
QuicPacket* packet = NULL;
QuicFrames frames;
QuicFecGroupNumber current_fec_group = 0;
QuicFecData fec_data;
size_t num_data_packets = options_.max_num_packets;
if (options_.use_fec) {
DCHECK_LT(1u, options_.max_num_packets);
--num_data_packets;
DCHECK(!fec_group_.get());
fec_group_.reset(new QuicFecGroup);
current_fec_group = fec_group_number_;
fec_data.fec_group = current_fec_group;
fec_data.min_protected_packet_sequence_number = sequence_number_ + 1;
}
size_t unconsumed_bytes = data.size();
if (data.size() != 0) {
size_t max_frame_len = framer_->GetMaxPlaintextSize(
options_.max_packet_length -
QuicUtils::StreamFramePacketOverhead(1));
DCHECK_GT(max_frame_len, 0u);
size_t frame_len = min<size_t>(max_frame_len, unconsumed_bytes);
while (unconsumed_bytes > 0 && num_data_packets > 0) {
--num_data_packets;
bool set_fin = false;
if (unconsumed_bytes <= frame_len) { // last loop
frame_len = min(unconsumed_bytes, frame_len);
set_fin = fin;
}
StringPiece data_frame(data.data() + data.size() - unconsumed_bytes,
frame_len);
QuicStreamFrame frame(id, set_fin, offset, data_frame);
frames.push_back(QuicFrame(&frame));
FillPacketHeader(current_fec_group, PACKET_FLAGS_NONE, &header);
offset += frame_len;
unconsumed_bytes -= frame_len;
// Produce the data packet (which might fin the stream).
packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
DCHECK_GE(options_.max_packet_length, packet->length());
packets->push_back(make_pair(header.packet_sequence_number, packet));
frames.clear();
}
// If we haven't finished serializing all the data, don't set any final fin.
if (unconsumed_bytes > 0) {
fin = false;
}
}
// Create a new packet for the fin, if necessary.
if (fin && data.size() == 0) {
FillPacketHeader(current_fec_group, PACKET_FLAGS_NONE, &header);
QuicStreamFrame frame(id, true, offset, "");
frames.push_back(QuicFrame(&frame));
packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
packets->push_back(make_pair(header.packet_sequence_number, packet));
frames.clear();
}
// Create a new FEC packet, if necessary
if (current_fec_group != 0) {
FillPacketHeader(current_fec_group, PACKET_FLAGS_FEC, &header);
fec_data.redundancy = fec_group_->parity();
QuicPacket* fec_packet = framer_->ConstructFecPacket(header, fec_data);
DCHECK(fec_packet);
packets->push_back(make_pair(header.packet_sequence_number, fec_packet));
++fec_group_number_;
}
/*
if (options_.random_reorder) {
int32 seed = ACMRandom::HostnamePidTimeSeed();
ACMRandom random(seed);
DLOG(INFO) << "Seed " << seed;
vector<PacketPair> tmp_store;
tmp_store.swap(*packets);
while (tmp_store.size() != 0) {
int idx = random.Uniform(tmp_store.size());
packets->push_back(tmp_store[idx]);
tmp_store.erase(tmp_store.begin() + idx);
}
}
*/
fec_group_.reset(NULL);
DCHECK(options_.max_num_packets >= packets->size());
return data.size() - unconsumed_bytes;
}
QuicPacketCreator::PacketPair QuicPacketCreator::ResetStream(
QuicStreamId id,
QuicStreamOffset offset,
QuicErrorCode error) {
QuicPacketHeader header;
FillPacketHeader(0, PACKET_FLAGS_NONE, &header);
QuicRstStreamFrame close_frame(id, offset, error);
QuicFrames frames;
frames.push_back(QuicFrame(&close_frame));
QuicPacket* packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
return make_pair(header.packet_sequence_number, packet);
}
QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection(
QuicConnectionCloseFrame* close_frame) {
QuicPacketHeader header;
FillPacketHeader(0, PACKET_FLAGS_NONE, &header);
QuicFrames frames;
frames.push_back(QuicFrame(close_frame));
QuicPacket* packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
return make_pair(header.packet_sequence_number, packet);
}
QuicPacketCreator::PacketPair QuicPacketCreator::AckPacket(
QuicAckFrame* ack_frame) {
QuicPacketHeader header;
FillPacketHeader(0, PACKET_FLAGS_NONE, &header);
QuicFrames frames;
frames.push_back(QuicFrame(ack_frame));
QuicPacket* packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
return make_pair(header.packet_sequence_number, packet);
}
QuicPacketCreator::PacketPair QuicPacketCreator::CongestionFeedbackPacket(
QuicCongestionFeedbackFrame* feedback_frame) {
QuicPacketHeader header;
FillPacketHeader(0, PACKET_FLAGS_NONE, &header);
QuicFrames frames;
frames.push_back(QuicFrame(feedback_frame));
QuicPacket* packet = framer_->ConstructFrameDataPacket(header, frames);
DCHECK(packet);
return make_pair(header.packet_sequence_number, packet);
}
QuicPacketSequenceNumber QuicPacketCreator::SetNewSequenceNumber(
QuicPacket* packet) {
++sequence_number_;
framer_->WriteSequenceNumber(sequence_number_, packet);
return sequence_number_;
}
void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
QuicPacketFlags flags,
QuicPacketHeader* header) {
header->guid = guid_;
header->flags = flags;
header->packet_sequence_number = ++sequence_number_;
header->fec_group = fec_group;
}
} // namespace net