blob: c9392a69deecfc6a6f1c7cd3d506dabc93a90f0f [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_framer.h"
#include "base/hash_tables.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_data_reader.h"
#include "net/quic/quic_data_writer.h"
#include "net/quic/quic_utils.h"
using base::StringPiece;
using std::make_pair;
using std::map;
using std::numeric_limits;
namespace net {
namespace {
// Mask to select the lowest 48 bits of a sequence number.
const QuicPacketSequenceNumber kSequenceNumberMask =
GG_UINT64_C(0x0000FFFFFFFFFFFF);
// Returns the absolute value of the difference between |a| and |b|.
QuicPacketSequenceNumber Delta(QuicPacketSequenceNumber a,
QuicPacketSequenceNumber b) {
// Since these are unsigned numbers, we can't just return abs(a - b)
if (a < b) {
return b - a;
}
return a - b;
}
QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target,
QuicPacketSequenceNumber a,
QuicPacketSequenceNumber b) {
return (Delta(target, a) < Delta(target, b)) ? a : b;
}
} // namespace
QuicFramer::QuicFramer(QuicDecrypter* decrypter, QuicEncrypter* encrypter)
: visitor_(NULL),
fec_builder_(NULL),
error_(QUIC_NO_ERROR),
last_sequence_number_(0),
decrypter_(decrypter),
encrypter_(encrypter) {
}
QuicFramer::~QuicFramer() {}
bool CanTruncate(const QuicFrame& frame) {
if (frame.type == ACK_FRAME ||
frame.type == CONNECTION_CLOSE_FRAME) {
return true;
}
return false;
}
QuicPacket* QuicFramer::ConstructFrameDataPacket(
const QuicPacketHeader& header,
const QuicFrames& frames) {
size_t num_consumed = 0;
QuicPacket* packet =
ConstructMaxFrameDataPacket(header, frames, &num_consumed);
DCHECK_EQ(frames.size(), num_consumed);
return packet;
}
QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
const QuicPacketHeader& header,
const QuicFrames& frames,
size_t* num_consumed) {
DCHECK(!frames.empty());
// Compute the length of the packet. We use "magic numbers" here because
// sizeof(member_) is not necessarily the same as sizeof(member_wire_format).
const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize);
size_t len = kPacketHeaderSize;
bool truncating = false;
for (size_t i = 0; i < frames.size(); ++i) {
if (frames[i].type == PADDING_FRAME) {
// PADDING implies end of packet so make sure we don't have
// more frames on the list.
DCHECK_EQ(i, frames.size() - 1);
len = max_plaintext_size;
*num_consumed = i + 1;
break;
}
size_t frame_len = 1; // Space for the 8 bit type.
frame_len += ComputeFramePayloadLength(frames[i]);
if (len + frame_len > max_plaintext_size) {
// Only truncate the first frame in a packet, so if subsequent ones go
// over, stop including more frames.
if (i > 0) {
break;
}
if (CanTruncate(frames[0])) {
// Truncate the frame so the packet will not exceed kMaxPacketSize.
// Note that we may not use every byte of the writer in this case.
len = max_plaintext_size;
*num_consumed = 1;
truncating = true;
DLOG(INFO) << "Truncating large frame";
break;
} else {
return NULL;
}
}
len += frame_len;
*num_consumed = i + 1;
}
if (truncating) {
DCHECK_EQ(1u, *num_consumed);
}
QuicDataWriter writer(len);
if (!WritePacketHeader(header, &writer)) {
return NULL;
}
// frame count
if (*num_consumed > 256u) {
return NULL;
}
for (size_t i = 0; i < *num_consumed; ++i) {
const QuicFrame& frame = frames[i];
if (!writer.WriteUInt8(frame.type)) {
return NULL;
}
switch (frame.type) {
case PADDING_FRAME:
writer.WritePadding();
break;
case STREAM_FRAME:
if (!AppendStreamFramePayload(*frame.stream_frame, &writer)) {
return NULL;
}
break;
case ACK_FRAME:
if (!AppendAckFramePayload(*frame.ack_frame, &writer)) {
return NULL;
}
break;
case CONGESTION_FEEDBACK_FRAME:
if (!AppendQuicCongestionFeedbackFramePayload(
*frame.congestion_feedback_frame, &writer)) {
return NULL;
}
break;
case RST_STREAM_FRAME:
if (!AppendRstStreamFramePayload(*frame.rst_stream_frame, &writer)) {
return NULL;
}
break;
case CONNECTION_CLOSE_FRAME:
if (!AppendConnectionCloseFramePayload(
*frame.connection_close_frame, &writer)) {
return NULL;
}
break;
default:
RaiseError(QUIC_INVALID_FRAME_DATA);
return NULL;
}
}
DCHECK(truncating || len == writer.length());
// Save the length before writing, because take clears it.
len = writer.length();
QuicPacket* packet = QuicPacket::NewDataPacket(writer.take(), len, true);
if (fec_builder_) {
fec_builder_->OnBuiltFecProtectedPayload(header,
packet->FecProtectedData());
}
return packet;
}
QuicPacket* QuicFramer::ConstructFecPacket(const QuicPacketHeader& header,
const QuicFecData& fec) {
size_t len = kPacketHeaderSize;
len += fec.redundancy.length();
QuicDataWriter writer(len);
if (!WritePacketHeader(header, &writer)) {
return NULL;
}
if (!writer.WriteBytes(fec.redundancy.data(), fec.redundancy.length())) {
return NULL;
}
return QuicPacket::NewFecPacket(writer.take(), len, true);
}
// static
QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
const QuicPublicResetPacket& packet) {
DCHECK_EQ(PACKET_PUBLIC_FLAGS_RST,
PACKET_PUBLIC_FLAGS_RST & packet.public_header.flags);
size_t len = kPublicResetPacketSize;
QuicDataWriter writer(len);
if (!writer.WriteUInt64(packet.public_header.guid)) {
return NULL;
}
uint8 flags = static_cast<uint8>(packet.public_header.flags);
if (!writer.WriteUInt8(flags)) {
return NULL;
}
if (!writer.WriteUInt64(packet.nonce_proof)) {
return NULL;
}
if (!AppendPacketSequenceNumber(packet.rejected_sequence_number,
&writer)) {
return NULL;
}
return new QuicEncryptedPacket(writer.take(), len, true);
}
// TODO(satyamshekhar): Framer doesn't need addresses. Get rid of them.
bool QuicFramer::ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
DCHECK(!reader_.get());
reader_.reset(new QuicDataReader(packet.data(), packet.length()));
// First parse the public header.
QuicPacketPublicHeader public_header;
if (!ProcessPublicHeader(&public_header)) {
DLOG(WARNING) << "Unable to process public header.";
reader_.reset(NULL);
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
bool rv;
if (public_header.flags & PACKET_PUBLIC_FLAGS_RST) {
rv = ProcessPublicResetPacket(public_header);
} else {
rv = ProcessDataPacket(public_header, self_address, peer_address, packet);
}
reader_.reset(NULL);
return rv;
}
bool QuicFramer::ProcessDataPacket(
const QuicPacketPublicHeader& public_header,
const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
visitor_->OnPacket(self_address, peer_address);
QuicPacketHeader header(public_header);
if (!ProcessPacketHeader(&header, packet)) {
DLOG(WARNING) << "Unable to process data packet header.";
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
if (!visitor_->OnPacketHeader(header)) {
return true;
}
if (packet.length() > kMaxPacketSize) {
DLOG(WARNING) << "Packet too large: " << packet.length();
return RaiseError(QUIC_PACKET_TOO_LARGE);
}
// Handle the payload.
if ((header.private_flags & PACKET_PRIVATE_FLAGS_FEC) == 0) {
if (header.fec_group != 0) {
StringPiece payload = reader_->PeekRemainingPayload();
visitor_->OnFecProtectedPayload(payload);
}
if (!ProcessFrameData()) {
DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error.
DLOG(WARNING) << "Unable to process frame data.";
return false;
}
} else {
QuicFecData fec_data;
fec_data.fec_group = header.fec_group;
fec_data.redundancy = reader_->ReadRemainingPayload();
visitor_->OnFecData(fec_data);
}
visitor_->OnPacketComplete();
return true;
}
bool QuicFramer::ProcessPublicResetPacket(
const QuicPacketPublicHeader& public_header) {
QuicPublicResetPacket packet(public_header);
if (!reader_->ReadUInt64(&packet.nonce_proof)) {
set_detailed_error("Unable to read nonce proof.");
return false;
}
// TODO(satyamshekhar): validate nonce to protect against DoS.
if (!reader_->ReadUInt48(&packet.rejected_sequence_number)) {
set_detailed_error("Unable to read rejected sequence number.");
return false;
}
visitor_->OnPublicResetPacket(packet);
return true;
}
bool QuicFramer::ProcessRevivedPacket(const QuicPacketHeader& header,
StringPiece payload) {
DCHECK(!reader_.get());
visitor_->OnRevivedPacket();
visitor_->OnPacketHeader(header);
if (payload.length() > kMaxPacketSize) {
set_detailed_error("Revived packet too large.");
return RaiseError(QUIC_PACKET_TOO_LARGE);
}
reader_.reset(new QuicDataReader(payload.data(), payload.length()));
if (!ProcessFrameData()) {
DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error.
DLOG(WARNING) << "Unable to process frame data.";
return false;
}
visitor_->OnPacketComplete();
reader_.reset(NULL);
return true;
}
bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
QuicDataWriter* writer) {
if (!writer->WriteUInt64(header.public_header.guid)) {
return false;
}
uint8 flags = static_cast<uint8>(header.public_header.flags);
if (!writer->WriteUInt8(flags)) {
return false;
}
if (!AppendPacketSequenceNumber(header.packet_sequence_number, writer)) {
return false;
}
flags = static_cast<uint8>(header.private_flags);
if (!writer->WriteUInt8(flags)) {
return false;
}
// Offset from the current packet sequence number to the first fec
// protected packet, or kNoFecOffset to signal no FEC protection.
uint8 first_fec_protected_packet_offset = kNoFecOffset;
// The FEC group number is the sequence number of the first fec
// protected packet, or 0 if this packet is not protected.
if (header.fec_group != 0) {
DCHECK_GE(header.packet_sequence_number, header.fec_group);
DCHECK_GT(255u, header.packet_sequence_number - header.fec_group);
first_fec_protected_packet_offset =
header.packet_sequence_number - header.fec_group;
}
if (!writer->WriteBytes(&first_fec_protected_packet_offset, 1)) {
return false;
}
return true;
}
QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire(
QuicPacketSequenceNumber packet_sequence_number) const {
// The new sequence number might have wrapped to the next epoc, or
// it might have reverse wrapped to the previous epoch, or it might
// remain in the same epoch. Select the sequence number closest to the
// previous sequence number.
QuicPacketSequenceNumber epoch = last_sequence_number_ & ~kSequenceNumberMask;
QuicPacketSequenceNumber prev_epoch = epoch - (GG_UINT64_C(1) << 48);
QuicPacketSequenceNumber next_epoch = epoch + (GG_UINT64_C(1) << 48);
return ClosestTo(last_sequence_number_,
epoch + packet_sequence_number,
ClosestTo(last_sequence_number_,
prev_epoch + packet_sequence_number,
next_epoch + packet_sequence_number));
}
/* static */
bool QuicFramer::ReadGuidFromPacket(const QuicEncryptedPacket& packet,
QuicGuid* guid) {
QuicDataReader reader(packet.data(), packet.length());
return reader.ReadUInt64(guid);
}
bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
if (!reader_->ReadUInt64(&public_header->guid)) {
set_detailed_error("Unable to read GUID.");
return false;
}
uint8 public_flags;
if (!reader_->ReadBytes(&public_flags, 1)) {
set_detailed_error("Unable to read public flags.");
return false;
}
if (public_flags > PACKET_PUBLIC_FLAGS_MAX) {
set_detailed_error("Illegal public flags value.");
return false;
}
public_header->flags = static_cast<QuicPacketPublicFlags>(public_flags);
return true;
}
bool QuicFramer::ProcessPacketHeader(
QuicPacketHeader* header,
const QuicEncryptedPacket& packet) {
if (!ProcessPacketSequenceNumber(&header->packet_sequence_number)) {
set_detailed_error("Unable to read sequence number.");
return false;
}
if (header->packet_sequence_number == 0u) {
set_detailed_error("Packet sequence numbers cannot be 0.");
return false;
}
if (!DecryptPayload(packet)) {
DLOG(WARNING) << "Unable to decrypt payload.";
return RaiseError(QUIC_DECRYPTION_FAILURE);
}
uint8 private_flags;
if (!reader_->ReadBytes(&private_flags, 1)) {
set_detailed_error("Unable to read private flags.");
return false;
}
if (private_flags > PACKET_PRIVATE_FLAGS_MAX) {
set_detailed_error("Illegal private flags value.");
return false;
}
header->private_flags = static_cast<QuicPacketPrivateFlags>(private_flags);
uint8 first_fec_protected_packet_offset;
if (!reader_->ReadBytes(&first_fec_protected_packet_offset, 1)) {
set_detailed_error("Unable to read first fec protected packet offset.");
return false;
}
header->fec_group = first_fec_protected_packet_offset == kNoFecOffset ? 0 :
header->packet_sequence_number - first_fec_protected_packet_offset;
// Set the last sequence number after we have decrypted the packet
// so we are confident is not attacker controlled.
last_sequence_number_ = header->packet_sequence_number;
return true;
}
bool QuicFramer::ProcessPacketSequenceNumber(
QuicPacketSequenceNumber* sequence_number) {
QuicPacketSequenceNumber wire_sequence_number;
if (!reader_->ReadUInt48(&wire_sequence_number)) {
return false;
}
*sequence_number =
CalculatePacketSequenceNumberFromWire(wire_sequence_number);
return true;
}
bool QuicFramer::ProcessFrameData() {
if (reader_->IsDoneReading()) {
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
while (!reader_->IsDoneReading()) {
uint8 frame_type;
if (!reader_->ReadBytes(&frame_type, 1)) {
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
switch (frame_type) {
case PADDING_FRAME:
// We're done with the packet
return true;
case STREAM_FRAME:
if (!ProcessStreamFrame()) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
break;
case ACK_FRAME: {
QuicAckFrame frame;
if (!ProcessAckFrame(&frame)) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
break;
}
case CONGESTION_FEEDBACK_FRAME: {
QuicCongestionFeedbackFrame frame;
if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
break;
}
case RST_STREAM_FRAME:
if (!ProcessRstStreamFrame()) {
return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
}
break;
case CONNECTION_CLOSE_FRAME:
if (!ProcessConnectionCloseFrame()) {
return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
break;
default:
set_detailed_error("Illegal frame type.");
DLOG(WARNING) << "Illegal frame type: "
<< static_cast<int>(frame_type);
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
}
return true;
}
bool QuicFramer::ProcessStreamFrame() {
QuicStreamFrame frame;
if (!reader_->ReadUInt32(&frame.stream_id)) {
set_detailed_error("Unable to read stream_id.");
return false;
}
uint8 fin;
if (!reader_->ReadBytes(&fin, 1)) {
set_detailed_error("Unable to read fin.");
return false;
}
if (fin > 1) {
set_detailed_error("Invalid fin value.");
return false;
}
frame.fin = (fin == 1);
if (!reader_->ReadUInt64(&frame.offset)) {
set_detailed_error("Unable to read offset.");
return false;
}
if (!reader_->ReadStringPiece16(&frame.data)) {
set_detailed_error("Unable to read frame data.");
return false;
}
visitor_->OnStreamFrame(frame);
return true;
}
bool QuicFramer::ProcessAckFrame(QuicAckFrame* frame) {
if (!ProcessSentInfo(&frame->sent_info)) {
return false;
}
if (!ProcessReceivedInfo(&frame->received_info)) {
return false;
}
visitor_->OnAckFrame(*frame);
return true;
}
bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) {
if (!ProcessPacketSequenceNumber(&received_info->largest_observed)) {
set_detailed_error("Unable to read largest observed.");
return false;
}
uint8 num_missing_packets;
if (!reader_->ReadBytes(&num_missing_packets, 1)) {
set_detailed_error("Unable to read num missing packets.");
return false;
}
for (int i = 0; i < num_missing_packets; ++i) {
QuicPacketSequenceNumber sequence_number;
if (!ProcessPacketSequenceNumber(&sequence_number)) {
set_detailed_error("Unable to read sequence number in missing packets.");
return false;
}
received_info->missing_packets.insert(sequence_number);
}
return true;
}
bool QuicFramer::ProcessSentInfo(SentPacketInfo* sent_info) {
if (!ProcessPacketSequenceNumber(&sent_info->least_unacked)) {
set_detailed_error("Unable to read least unacked.");
return false;
}
return true;
}
bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
QuicCongestionFeedbackFrame* frame) {
uint8 feedback_type;
if (!reader_->ReadBytes(&feedback_type, 1)) {
set_detailed_error("Unable to read congestion feedback type.");
return false;
}
frame->type =
static_cast<CongestionFeedbackType>(feedback_type);
switch (frame->type) {
case kInterArrival: {
CongestionFeedbackMessageInterArrival* inter_arrival =
&frame->inter_arrival;
if (!reader_->ReadUInt16(
&inter_arrival->accumulated_number_of_lost_packets)) {
set_detailed_error(
"Unable to read accumulated number of lost packets.");
return false;
}
uint8 num_received_packets;
if (!reader_->ReadBytes(&num_received_packets, 1)) {
set_detailed_error("Unable to read num received packets.");
return false;
}
if (num_received_packets > 0u) {
uint64 smallest_received;
if (!ProcessPacketSequenceNumber(&smallest_received)) {
set_detailed_error("Unable to read smallest received.");
return false;
}
uint64 time_received_us;
if (!reader_->ReadUInt64(&time_received_us)) {
set_detailed_error("Unable to read time received.");
return false;
}
inter_arrival->received_packet_times.insert(
make_pair(smallest_received,
QuicTime::FromMicroseconds(time_received_us)));
for (int i = 0; i < num_received_packets - 1; ++i) {
uint16 sequence_delta;
if (!reader_->ReadUInt16(&sequence_delta)) {
set_detailed_error(
"Unable to read sequence delta in received packets.");
return false;
}
int32 time_delta_us;
if (!reader_->ReadBytes(&time_delta_us, sizeof(time_delta_us))) {
set_detailed_error(
"Unable to read time delta in received packets.");
return false;
}
QuicPacketSequenceNumber packet = smallest_received + sequence_delta;
inter_arrival->received_packet_times.insert(
make_pair(packet, QuicTime::FromMicroseconds(time_received_us +
time_delta_us)));
}
}
break;
}
case kFixRate: {
CongestionFeedbackMessageFixRate* fix_rate = &frame->fix_rate;
if (!reader_->ReadUInt32(&fix_rate->bitrate_in_bytes_per_second)) {
set_detailed_error("Unable to read bitrate.");
return false;
}
break;
}
case kTCP: {
CongestionFeedbackMessageTCP* tcp = &frame->tcp;
if (!reader_->ReadUInt16(&tcp->accumulated_number_of_lost_packets)) {
set_detailed_error(
"Unable to read accumulated number of lost packets.");
return false;
}
if (!reader_->ReadUInt16(&tcp->receive_window)) {
set_detailed_error("Unable to read receive window.");
return false;
}
break;
}
default:
set_detailed_error("Illegal congestion feedback type.");
DLOG(WARNING) << "Illegal congestion feedback type: "
<< frame->type;
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
visitor_->OnCongestionFeedbackFrame(*frame);
return true;
}
bool QuicFramer::ProcessRstStreamFrame() {
QuicRstStreamFrame frame;
if (!reader_->ReadUInt32(&frame.stream_id)) {
set_detailed_error("Unable to read stream_id.");
return false;
}
if (!reader_->ReadUInt64(&frame.offset)) {
set_detailed_error("Unable to read offset in rst frame.");
return false;
}
uint32 error_code;
if (!reader_->ReadUInt32(&error_code)) {
set_detailed_error("Unable to read rst stream error code.");
return false;
}
frame.error_code = static_cast<QuicErrorCode>(error_code);
StringPiece error_details;
if (!reader_->ReadStringPiece16(&error_details)) {
set_detailed_error("Unable to read rst stream error details.");
return false;
}
frame.error_details = error_details.as_string();
visitor_->OnRstStreamFrame(frame);
return true;
}
bool QuicFramer::ProcessConnectionCloseFrame() {
QuicConnectionCloseFrame frame;
uint32 error_code;
if (!reader_->ReadUInt32(&error_code)) {
set_detailed_error("Unable to read connection close error code.");
return false;
}
frame.error_code = static_cast<QuicErrorCode>(error_code);
StringPiece error_details;
if (!reader_->ReadStringPiece16(&error_details)) {
set_detailed_error("Unable to read connection close error details.");
return false;
}
frame.error_details = error_details.as_string();
if (!ProcessAckFrame(&frame.ack_frame)) {
DLOG(WARNING) << "Unable to process ack frame.";
return false;
}
visitor_->OnConnectionCloseFrame(frame);
return true;
}
QuicEncryptedPacket* QuicFramer::EncryptPacket(const QuicPacket& packet) {
scoped_ptr<QuicData> out(encrypter_->Encrypt(packet.AssociatedData(),
packet.Plaintext()));
if (out.get() == NULL) {
RaiseError(QUIC_ENCRYPTION_FAILURE);
return NULL;
}
size_t len = kStartOfEncryptedData + out->length();
char* buffer = new char[len];
// TODO(rch): eliminate this buffer copy by passing in a buffer to Encrypt().
memcpy(buffer, packet.data(), kStartOfEncryptedData);
memcpy(buffer + kStartOfEncryptedData, out->data(), out->length());
return new QuicEncryptedPacket(buffer, len, true);
}
size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) {
return encrypter_->GetMaxPlaintextSize(ciphertext_size);
}
bool QuicFramer::DecryptPayload(const QuicEncryptedPacket& packet) {
StringPiece encrypted;
if (!reader_->ReadStringPiece(&encrypted, reader_->BytesRemaining())) {
return false;
}
DCHECK(decrypter_.get() != NULL);
decrypted_.reset(decrypter_->Decrypt(packet.AssociatedData(), encrypted));
if (decrypted_.get() == NULL) {
return false;
}
reader_.reset(new QuicDataReader(decrypted_->data(), decrypted_->length()));
return true;
}
size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) {
size_t len = 0;
// We use "magic numbers" here because sizeof(member_) is not necessarily the
// same as sizeof(member_wire_format).
switch (frame.type) {
case STREAM_FRAME:
len += 4; // stream id
len += 1; // fin
len += 8; // offset
len += 2; // space for the 16 bit length
len += frame.stream_frame->data.size();
break;
case ACK_FRAME: {
const QuicAckFrame& ack = *frame.ack_frame;
len += 6; // largest observed packet sequence number
len += 1; // num missing packets
len += 6 * ack.received_info.missing_packets.size();
len += 6; // least packet sequence number awaiting an ack
break;
}
case CONGESTION_FEEDBACK_FRAME: {
const QuicCongestionFeedbackFrame& congestion_feedback =
*frame.congestion_feedback_frame;
len += 1; // congestion feedback type
switch (congestion_feedback.type) {
case kInterArrival: {
const CongestionFeedbackMessageInterArrival& inter_arrival =
congestion_feedback.inter_arrival;
len += 2;
len += 1; // num received packets
if (inter_arrival.received_packet_times.size() > 0) {
len += 6; // smallest received
len += 8; // time
// 2 bytes per sequence number delta plus 4 bytes per delta time.
len += 6 * (inter_arrival.received_packet_times.size() - 1);
}
break;
}
case kFixRate:
len += 4;
break;
case kTCP:
len += 4;
break;
default:
set_detailed_error("Illegal feedback type.");
DLOG(INFO) << "Illegal feedback type: " << congestion_feedback.type;
break;
}
break;
}
case RST_STREAM_FRAME:
len += 4; // stream id
len += 8; // offset
len += 4; // error code
len += 2; // error details size
len += frame.rst_stream_frame->error_details.size();
break;
case CONNECTION_CLOSE_FRAME:
len += 4; // error code
len += 2; // error details size
len += frame.connection_close_frame->error_details.size();
len += ComputeFramePayloadLength(
QuicFrame(&frame.connection_close_frame->ack_frame));
break;
default:
set_detailed_error("Illegal frame type.");
DLOG(INFO) << "Illegal frame type: " << frame.type;
break;
}
return len;
}
// static
bool QuicFramer::AppendPacketSequenceNumber(
QuicPacketSequenceNumber packet_sequence_number,
QuicDataWriter* writer) {
// Ensure the entire sequence number can be written.
if (writer->capacity() - writer->length() < kSequenceNumberSize) {
return false;
}
return writer->WriteUInt48(packet_sequence_number & kSequenceNumberMask);
}
bool QuicFramer::AppendStreamFramePayload(
const QuicStreamFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteUInt32(frame.stream_id)) {
return false;
}
if (!writer->WriteUInt8(frame.fin)) {
return false;
}
if (!writer->WriteUInt64(frame.offset)) {
return false;
}
if (!writer->WriteUInt16(frame.data.size())) {
return false;
}
if (!writer->WriteBytes(frame.data.data(),
frame.data.size())) {
return false;
}
return true;
}
QuicPacketSequenceNumber QuicFramer::CalculateLargestObserved(
const SequenceSet& missing_packets,
SequenceSet::const_iterator largest_written) {
SequenceSet::const_iterator it = largest_written;
QuicPacketSequenceNumber previous_missing = *it;
++it;
// See if the next thing is a gap in the missing packets: if it's a
// non-missing packet we can return it.
if (it != missing_packets.end() && previous_missing + 1 != *it) {
return *it - 1;
}
// Otherwise return the largest missing packet, as indirectly observed.
return *largest_written;
}
// TODO(ianswett): Use varints or another more compact approach for all deltas.
bool QuicFramer::AppendAckFramePayload(
const QuicAckFrame& frame,
QuicDataWriter* writer) {
if (!AppendPacketSequenceNumber(frame.sent_info.least_unacked, writer)) {
return false;
}
size_t largest_observed_offset = writer->length();
if (!AppendPacketSequenceNumber(frame.received_info.largest_observed,
writer)) {
return false;
}
// We don't check for overflowing uint8 here, because we only can fit 192 acks
// per packet, so if we overflow we will be truncated.
uint8 num_missing_packets = frame.received_info.missing_packets.size();
size_t num_missing_packets_offset = writer->length();
if (!writer->WriteBytes(&num_missing_packets, 1)) {
return false;
}
SequenceSet::const_iterator it = frame.received_info.missing_packets.begin();
int num_missing_packets_written = 0;
for (; it != frame.received_info.missing_packets.end(); ++it) {
if (!AppendPacketSequenceNumber(*it, writer)) {
// We are truncating. Overwrite largest_observed.
QuicPacketSequenceNumber largest_observed =
CalculateLargestObserved(frame.received_info.missing_packets, --it);
writer->WriteUInt48ToOffset(largest_observed & kSequenceNumberMask,
largest_observed_offset);
writer->WriteUInt8ToOffset(num_missing_packets_written,
num_missing_packets_offset);
return true;
}
++num_missing_packets_written;
DCHECK_GE(numeric_limits<uint8>::max(), num_missing_packets_written);
}
return true;
}
bool QuicFramer::AppendQuicCongestionFeedbackFramePayload(
const QuicCongestionFeedbackFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteBytes(&frame.type, 1)) {
return false;
}
switch (frame.type) {
case kInterArrival: {
const CongestionFeedbackMessageInterArrival& inter_arrival =
frame.inter_arrival;
if (!writer->WriteUInt16(
inter_arrival.accumulated_number_of_lost_packets)) {
return false;
}
DCHECK_GE(numeric_limits<uint8>::max(),
inter_arrival.received_packet_times.size());
if (inter_arrival.received_packet_times.size() >
numeric_limits<uint8>::max()) {
return false;
}
// TODO(ianswett): Make num_received_packets a varint.
uint8 num_received_packets =
inter_arrival.received_packet_times.size();
if (!writer->WriteBytes(&num_received_packets, 1)) {
return false;
}
if (num_received_packets > 0) {
TimeMap::const_iterator it =
inter_arrival.received_packet_times.begin();
QuicPacketSequenceNumber lowest_sequence = it->first;
if (!AppendPacketSequenceNumber(lowest_sequence, writer)) {
return false;
}
QuicTime lowest_time = it->second;
// TODO(ianswett): Use time deltas from the connection's first received
// packet.
if (!writer->WriteUInt64(lowest_time.ToMicroseconds())) {
return false;
}
for (++it; it != inter_arrival.received_packet_times.end(); ++it) {
QuicPacketSequenceNumber sequence_delta = it->first - lowest_sequence;
DCHECK_GE(numeric_limits<uint16>::max(), sequence_delta);
if (sequence_delta > numeric_limits<uint16>::max()) {
return false;
}
if (!writer->WriteUInt16(static_cast<uint16>(sequence_delta))) {
return false;
}
int32 time_delta_us =
it->second.Subtract(lowest_time).ToMicroseconds();
if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) {
return false;
}
}
}
break;
}
case kFixRate: {
const CongestionFeedbackMessageFixRate& fix_rate =
frame.fix_rate;
if (!writer->WriteUInt32(fix_rate.bitrate_in_bytes_per_second)) {
return false;
}
break;
}
case kTCP: {
const CongestionFeedbackMessageTCP& tcp = frame.tcp;
if (!writer->WriteUInt16(tcp.accumulated_number_of_lost_packets)) {
return false;
}
if (!writer->WriteUInt16(tcp.receive_window)) {
return false;
}
break;
}
default:
return false;
}
return true;
}
bool QuicFramer::AppendRstStreamFramePayload(
const QuicRstStreamFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteUInt32(frame.stream_id)) {
return false;
}
if (!writer->WriteUInt64(frame.offset)) {
return false;
}
uint32 error_code = static_cast<uint32>(frame.error_code);
if (!writer->WriteUInt32(error_code)) {
return false;
}
if (!writer->WriteStringPiece16(frame.error_details)) {
return false;
}
return true;
}
bool QuicFramer::AppendConnectionCloseFramePayload(
const QuicConnectionCloseFrame& frame,
QuicDataWriter* writer) {
uint32 error_code = static_cast<uint32>(frame.error_code);
if (!writer->WriteUInt32(error_code)) {
return false;
}
if (!writer->WriteStringPiece16(frame.error_details)) {
return false;
}
AppendAckFramePayload(frame.ack_frame, writer);
return true;
}
bool QuicFramer::RaiseError(QuicErrorCode error) {
DLOG(INFO) << detailed_error_;
set_error(error);
visitor_->OnError(this);
reader_.reset(NULL);
return false;
}
} // namespace net