| Index: net/quic/quic_framer.cc
|
| diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e392306e282cfe85f0e653d5c09eeaee943a2b34
|
| --- /dev/null
|
| +++ b/net/quic/quic_framer.cc
|
| @@ -0,0 +1,784 @@
|
| +// 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::hash_set;
|
| +using base::StringPiece;
|
| +
|
| +namespace net {
|
| +
|
| +QuicFramer::QuicFramer(QuicDecrypter* decrypter, QuicEncrypter* encrypter)
|
| + : visitor_(NULL),
|
| + fec_builder_(NULL),
|
| + error_(QUIC_NO_ERROR),
|
| + decrypter_(decrypter),
|
| + encrypter_(encrypter) {
|
| +}
|
| +
|
| +QuicFramer::~QuicFramer() {}
|
| +
|
| +bool QuicFramer::ConstructFragementDataPacket(
|
| + const QuicPacketHeader& header,
|
| + const QuicFragments& fragments,
|
| + QuicPacket** packet) {
|
| + // Compute the length of the packet. We use "magic numbers" here because
|
| + // sizeof(member_) is not necessairly the same as sizeof(member_wire_format).
|
| + size_t len = kPacketHeaderSize;
|
| + len += 1; // fragment count
|
| + for (size_t i = 0; i < fragments.size(); ++i) {
|
| + len += 1; // space for the 8 bit type
|
| + len += ComputeFragmentPayloadLength(fragments[i]);
|
| + }
|
| +
|
| + QuicDataWriter writer(len);
|
| +
|
| + if (!WritePacketHeader(header, &writer)) {
|
| + return false;
|
| + }
|
| +
|
| + // fragment count
|
| + DCHECK_GE(256u, fragments.size());
|
| + if (!writer.WriteUInt8(fragments.size())) {
|
| + return false;
|
| + }
|
| +
|
| + for (size_t i = 0; i < fragments.size(); ++i) {
|
| + const QuicFragment& fragment = fragments[i];
|
| + if (!writer.WriteUInt8(fragment.type)) {
|
| + return false;
|
| + }
|
| +
|
| + switch (fragment.type) {
|
| + case STREAM_FRAGMENT:
|
| + if (!AppendStreamFragmentPayload(*fragment.stream_fragment,
|
| + &writer)) {
|
| + return false;
|
| + }
|
| + break;
|
| + case PDU_FRAGMENT:
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + case ACK_FRAGMENT:
|
| + if (!AppendAckFragmentPayload(*fragment.ack_fragment, &writer)) {
|
| + return false;
|
| + }
|
| + break;
|
| + case RST_STREAM_FRAGMENT:
|
| + if (!AppendRstStreamFragmentPayload(*fragment.rst_stream_fragment,
|
| + &writer)) {
|
| + return false;
|
| + }
|
| + break;
|
| + case CONNECTION_CLOSE_FRAGMENT:
|
| + if (!AppendConnectionCloseFragmentPayload(
|
| + *fragment.connection_close_fragment, &writer)) {
|
| + return false;
|
| + }
|
| + break;
|
| + default:
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + }
|
| +
|
| + *packet = new QuicPacket(writer.take(), len, true);
|
| + if (fec_builder_) {
|
| + fec_builder_->OnBuiltFecProtectedPayload(header,
|
| + (*packet)->FecProtectedData());
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ConstructFecPacket(const QuicPacketHeader& header,
|
| + const QuicFecData& fec,
|
| + QuicPacket** packet) {
|
| + // Compute the length of the packet. We use "magic numbers" here because
|
| + // sizeof(member_) is not necessairly the same as sizeof(member_wire_format).
|
| + size_t len = kPacketHeaderSize;
|
| + len += 6; // first protected packet sequence number
|
| + len += fec.redundancy.length();
|
| +
|
| + QuicDataWriter writer(len);
|
| +
|
| + if (!WritePacketHeader(header, &writer)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!writer.WriteUInt48(fec.first_protected_packet_sequence_number)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!writer.WriteBytes(fec.redundancy.data(), fec.redundancy.length())) {
|
| + return false;
|
| + }
|
| +
|
| + *packet = new QuicPacket(writer.take(), len, true);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void QuicFramer::IncrementRetransmitCount(QuicPacket* packet) {
|
| + CHECK_GT(packet->length(), kPacketHeaderSize);
|
| +
|
| + ++packet->mutable_data()[kRetransmissionOffset];
|
| +}
|
| +
|
| +uint8 QuicFramer::GetRetransmitCount(QuicPacket* packet) {
|
| + CHECK_GT(packet->length(), kPacketHeaderSize);
|
| +
|
| + return packet->mutable_data()[kRetransmissionOffset];
|
| +}
|
| +
|
| +bool QuicFramer::ProcessPacket(const IPEndPoint& peer_address,
|
| + const QuicEncryptedPacket& packet) {
|
| + DCHECK(!reader_.get());
|
| + reader_.reset(new QuicDataReader(packet.data(), packet.length()));
|
| + visitor_->OnPacket(peer_address);
|
| +
|
| + // First parse the packet header.
|
| + QuicPacketHeader header;
|
| + if (!ProcessPacketHeader(&header, packet)) {
|
| + DLOG(WARNING) << "Unable to process header.";
|
| + return RaiseError(QUIC_INVALID_PACKET_HEADER);
|
| + }
|
| +
|
| + if (!visitor_->OnPacketHeader(header)) {
|
| + reader_.reset(NULL);
|
| + return true;
|
| + }
|
| +
|
| + if (packet.length() > kMaxPacketSize) {
|
| + DLOG(WARNING) << "Packet too large: " << packet.length();
|
| + return RaiseError(QUIC_PACKET_TOO_LARGE);
|
| + }
|
| +
|
| + // Handle the payload.
|
| + if ((header.flags & PACKET_FLAGS_FEC) == 0) {
|
| + if (header.fec_group != 0) {
|
| + StringPiece payload = reader_->PeekRemainingPayload();
|
| + visitor_->OnFecProtectedPayload(payload);
|
| + }
|
| + if (!ProcessFragmentData()) {
|
| + DLOG(WARNING) << "Unable to process fragment data.";
|
| + return false;
|
| + }
|
| + } else {
|
| + QuicFecData fec_data;
|
| + fec_data.fec_group = header.fec_group;
|
| + if (!reader_->ReadUInt48(
|
| + &fec_data.first_protected_packet_sequence_number)) {
|
| + set_detailed_error("Unable to read first protected packet.");
|
| + return false;
|
| + }
|
| +
|
| + fec_data.redundancy = reader_->ReadRemainingPayload();
|
| + visitor_->OnFecData(fec_data);
|
| + }
|
| +
|
| + visitor_->OnPacketComplete();
|
| + reader_.reset(NULL);
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessRevivedPacket(const IPEndPoint& peer_address,
|
| + const QuicPacketHeader& header,
|
| + StringPiece payload) {
|
| + DCHECK(!reader_.get());
|
| +
|
| + visitor_->OnPacket(peer_address);
|
| +
|
| + 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 (!ProcessFragmentData()) {
|
| + DLOG(WARNING) << "Unable to process fragment data.";
|
| + return false;
|
| + }
|
| +
|
| + visitor_->OnPacketComplete();
|
| + reader_.reset(NULL);
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header,
|
| + QuicDataWriter* writer) {
|
| + // ConnectionHeader
|
| + if (!writer->WriteUInt64(header.guid)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!writer->WriteUInt48(header.packet_sequence_number)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!writer->WriteBytes(&header.retransmission_count, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + // CongestionMonitoredHeader
|
| + if (!writer->WriteUInt64(header.transmission_time)) {
|
| + return false;
|
| + }
|
| +
|
| + uint8 flags = static_cast<uint8>(header.flags);
|
| + if (!writer->WriteBytes(&flags, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!writer->WriteBytes(&header.fec_group, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessPacketHeader(QuicPacketHeader* header,
|
| + const QuicEncryptedPacket& packet) {
|
| + // ConnectionHeader
|
| + if (!reader_->ReadUInt64(&header->guid)) {
|
| + set_detailed_error("Unable to read GUID.");
|
| + return false;
|
| + }
|
| +
|
| + if (!reader_->ReadUInt48(&header->packet_sequence_number)) {
|
| + set_detailed_error("Unable to read sequence number.");
|
| + return false;
|
| + }
|
| +
|
| + if (!reader_->ReadBytes(&header->retransmission_count, 1)) {
|
| + set_detailed_error("Unable to read retransmission count.");
|
| + return false;
|
| + }
|
| +
|
| + // CongestionMonitoredHeader
|
| + if (!reader_->ReadUInt64(&header->transmission_time)) {
|
| + set_detailed_error("Unable to read transmission time.");
|
| + return false;
|
| + }
|
| +
|
| + unsigned char flags;
|
| + if (!reader_->ReadBytes(&flags, 1)) {
|
| + set_detailed_error("Unable to read flags.");
|
| + return false;
|
| + }
|
| +
|
| + if (flags > PACKET_FLAGS_MAX) {
|
| + set_detailed_error("Illegal flags value.");
|
| + return false;
|
| + }
|
| +
|
| + header->flags = static_cast<QuicPacketFlags>(flags);
|
| +
|
| + if (!DecryptPayload(packet)) {
|
| + DLOG(WARNING) << "Unable to decrypt payload.";
|
| + return RaiseError(QUIC_DECRYPTION_FAILURE);
|
| + }
|
| +
|
| + if (!reader_->ReadBytes(&header->fec_group, 1)) {
|
| + set_detailed_error("Unable to read fec group.");
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessFragmentData() {
|
| + uint8 fragment_count;
|
| + if (!reader_->ReadBytes(&fragment_count, 1)) {
|
| + set_detailed_error("Unable to read fragment count.");
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| +
|
| + for (uint8 i = 0; i < fragment_count; ++i) {
|
| + uint8 fragment_type;
|
| + if (!reader_->ReadBytes(&fragment_type, 1)) {
|
| + set_detailed_error("Unable to read fragment type.");
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + switch (fragment_type) {
|
| + case STREAM_FRAGMENT:
|
| + if (!ProcessStreamFragment()) {
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + break;
|
| + case PDU_FRAGMENT:
|
| + if (!ProcessPDUFragment()) {
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + break;
|
| + case ACK_FRAGMENT: {
|
| + QuicAckFragment fragment;
|
| + if (!ProcessAckFragment(&fragment)) {
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + break;
|
| + }
|
| + case RST_STREAM_FRAGMENT:
|
| + if (!ProcessRstStreamFragment()) {
|
| + return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
|
| + }
|
| + break;
|
| + case CONNECTION_CLOSE_FRAGMENT:
|
| + if (!ProcessConnectionCloseFragment()) {
|
| + return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
|
| + }
|
| + break;
|
| + default:
|
| + set_detailed_error("Illegal fragment type.");
|
| + DLOG(WARNING) << "Illegal fragment type: " << (int)fragment_type;
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessStreamFragment() {
|
| + QuicStreamFragment fragment;
|
| + if (!reader_->ReadUInt32(&fragment.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;
|
| + }
|
| + fragment.fin = (fin == 1);
|
| +
|
| + if (!reader_->ReadUInt64(&fragment.offset)) {
|
| + set_detailed_error("Unable to read offset.");
|
| + return false;
|
| + }
|
| +
|
| + if (!reader_->ReadStringPiece16(&fragment.data)) {
|
| + set_detailed_error("Unable to read fragment data.");
|
| + return false;
|
| + }
|
| +
|
| + visitor_->OnStreamFragment(fragment);
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessPDUFragment() {
|
| + return false;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessAckFragment(QuicAckFragment* fragment) {
|
| + if (!reader_->ReadUInt48(&fragment->received_info.largest_received)) {
|
| + set_detailed_error("Unable to read largest received.");
|
| + return false;
|
| + }
|
| +
|
| + if (!reader_->ReadUInt64(&fragment->received_info.time_received)) {
|
| + set_detailed_error("Unable to read time received.");
|
| + return false;
|
| + }
|
| +
|
| + uint8 num_unacked_packets;
|
| + if (!reader_->ReadBytes(&num_unacked_packets, 1)) {
|
| + set_detailed_error("Unable to read num unacked packets.");
|
| + return false;
|
| + }
|
| +
|
| + for (int i = 0; i < num_unacked_packets; ++i) {
|
| + QuicPacketSequenceNumber sequence_number;
|
| + if (!reader_->ReadUInt48(&sequence_number)) {
|
| + set_detailed_error("Unable to read sequence number in unacked packets.");
|
| + return false;
|
| + }
|
| + fragment->received_info.missing_packets.insert(sequence_number);
|
| + }
|
| +
|
| + if (!reader_->ReadUInt48(&fragment->sent_info.least_unacked)) {
|
| + set_detailed_error("Unable to read least unacked.");
|
| + return false;
|
| + }
|
| +
|
| + uint8 num_non_retransmiting_packets;
|
| + if (!reader_->ReadBytes(&num_non_retransmiting_packets, 1)) {
|
| + set_detailed_error("Unable to read num non-retransmitting.");
|
| + return false;
|
| + }
|
| + for (uint8 i = 0; i < num_non_retransmiting_packets; ++i) {
|
| + QuicPacketSequenceNumber sequence_number;
|
| + if (!reader_->ReadUInt48(&sequence_number)) {
|
| + set_detailed_error(
|
| + "Unable to read sequence number in non-retransmitting.");
|
| + return false;
|
| + }
|
| + fragment->sent_info.non_retransmiting.insert(sequence_number);
|
| + }
|
| +
|
| + uint8 congestion_info_type;
|
| + if (!reader_->ReadBytes(&congestion_info_type, 1)) {
|
| + set_detailed_error("Unable to read congestion info type.");
|
| + return false;
|
| + }
|
| + fragment->congestion_info.type =
|
| + static_cast<CongestionFeedbackType>(congestion_info_type);
|
| +
|
| + switch (fragment->congestion_info.type) {
|
| + case kNone:
|
| + break;
|
| + case kInterArrival: {
|
| + CongestionFeedbackMessageInterArrival* inter_arrival =
|
| + &fragment->congestion_info.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;
|
| + }
|
| + if (!reader_->ReadBytes(&inter_arrival->offset_time, 2)) {
|
| + set_detailed_error("Unable to read offset time.");
|
| + return false;
|
| + }
|
| + if (!reader_->ReadUInt16(&inter_arrival->delta_time)) {
|
| + set_detailed_error("Unable to read delta time.");
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + case kFixRate: {
|
| + CongestionFeedbackMessageFixRate* fix_rate =
|
| + &fragment->congestion_info.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 = &fragment->congestion_info.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 info type.");
|
| + DLOG(WARNING) << "Illegal congestion info type: "
|
| + << fragment->congestion_info.type;
|
| + return RaiseError(QUIC_INVALID_FRAGMENT_DATA);
|
| + }
|
| +
|
| + visitor_->OnAckFragment(*fragment);
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessRstStreamFragment() {
|
| + QuicRstStreamFragment fragment;
|
| + if (!reader_->ReadUInt32(&fragment.stream_id)) {
|
| + set_detailed_error("Unable to read stream_id.");
|
| + return false;
|
| + }
|
| +
|
| + if (!reader_->ReadUInt64(&fragment.offset)) {
|
| + set_detailed_error("Unable to read offset in rst fragment.");
|
| + return false;
|
| + }
|
| +
|
| + uint32 details;
|
| + if (!reader_->ReadUInt32(&details)) {
|
| + set_detailed_error("Unable to read rst stream details.");
|
| + return false;
|
| + }
|
| + fragment.details = static_cast<QuicErrorCode>(details);
|
| +
|
| + visitor_->OnRstStreamFragment(fragment);
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::ProcessConnectionCloseFragment() {
|
| + QuicConnectionCloseFragment fragment;
|
| +
|
| + uint32 details;
|
| + if (!reader_->ReadUInt32(&details)) {
|
| + set_detailed_error("Unable to read connection close details.");
|
| + return false;
|
| + }
|
| + fragment.details = static_cast<QuicErrorCode>(details);
|
| +
|
| + if (!ProcessAckFragment(&fragment.ack_fragment)) {
|
| + DLOG(WARNING) << "Unable to process ack fragment.";
|
| + return false;
|
| + }
|
| +
|
| + visitor_->OnConnectionCloseFragment(fragment);
|
| + return true;
|
| +}
|
| +
|
| +void QuicFramer::WriteTransmissionTime(QuicTransmissionTime time,
|
| + QuicPacket* packet) {
|
| + QuicDataWriter::WriteUint64ToBuffer(
|
| + time, packet->mutable_data() + kTransmissionTimeOffset);
|
| +}
|
| +
|
| +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::ComputeFragmentPayloadLength(const QuicFragment& fragment) {
|
| + size_t len = 0;
|
| + // We use "magic numbers" here because sizeof(member_) is not necessairly the
|
| + // same as sizeof(member_wire_format).
|
| + switch (fragment.type) {
|
| + case STREAM_FRAGMENT:
|
| + len += 4; // stream id
|
| + len += 1; // fin
|
| + len += 8; // offset
|
| + len += 2; // space for the 16 bit length
|
| + len += fragment.stream_fragment->data.size();
|
| + break;
|
| + case PDU_FRAGMENT:
|
| + DLOG(INFO) << "PDU_FRAGMENT not yet supported";
|
| + break; // Need to support this eventually :>
|
| + case ACK_FRAGMENT: {
|
| + const QuicAckFragment& ack = *fragment.ack_fragment;
|
| + len += 6; // largest received packet sequence number
|
| + len += 8; // time delta
|
| + len += 1; // num missing packets
|
| + len += 6 * ack.received_info.missing_packets.size();
|
| + len += 6; // least packet sequence number awaiting an ack
|
| + len += 1; // num non retransmitting packets
|
| + len += 6 * ack.sent_info.non_retransmiting.size();
|
| + len += 1; // congestion control type
|
| + switch (ack.congestion_info.type) {
|
| + case kNone:
|
| + break;
|
| + case kInterArrival:
|
| + len += 6;
|
| + break;
|
| + case kFixRate:
|
| + len += 4;
|
| + break;
|
| + case kTCP:
|
| + len += 4;
|
| + break;
|
| + default:
|
| + set_detailed_error("Illegal feedback type.");
|
| + DLOG(INFO) << "Illegal feedback type: " << ack.congestion_info.type;
|
| + break;
|
| + }
|
| + break;
|
| + }
|
| + case RST_STREAM_FRAGMENT:
|
| + len += 4; // stream id
|
| + len += 8; // offset
|
| + len += 4; // details
|
| + break;
|
| + case CONNECTION_CLOSE_FRAGMENT:
|
| + len += 4; // details
|
| + len += ComputeFragmentPayloadLength(
|
| + QuicFragment(&fragment.connection_close_fragment->ack_fragment));
|
| + break;
|
| + default:
|
| + set_detailed_error("Illegal fragment type.");
|
| + DLOG(INFO) << "Illegal fragment type: " << fragment.type;
|
| + break;
|
| + }
|
| + return len;
|
| +}
|
| +
|
| +bool QuicFramer::AppendStreamFragmentPayload(
|
| + const QuicStreamFragment& fragment,
|
| + QuicDataWriter* writer) {
|
| + if (!writer->WriteUInt32(fragment.stream_id)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt8(fragment.fin)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt64(fragment.offset)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt16(fragment.data.size())) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteBytes(fragment.data.data(),
|
| + fragment.data.size())) {
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::AppendAckFragmentPayload(
|
| + const QuicAckFragment& fragment,
|
| + QuicDataWriter* writer) {
|
| + if (!writer->WriteUInt48(fragment.received_info.largest_received)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt64(fragment.received_info.time_received)) {
|
| + return false;
|
| + }
|
| +
|
| + size_t num_unacked_packets = fragment.received_info.missing_packets.size();
|
| + if (!writer->WriteBytes(&num_unacked_packets, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + hash_set<QuicPacketSequenceNumber>::const_iterator it =
|
| + fragment.received_info.missing_packets.begin();
|
| + for (; it != fragment.received_info.missing_packets.end(); ++it) {
|
| + if (!writer->WriteUInt48(*it)) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + if (!writer->WriteUInt48(fragment.sent_info.least_unacked)) {
|
| + return false;
|
| + }
|
| +
|
| + size_t num_non_retransmiting_packets =
|
| + fragment.sent_info.non_retransmiting.size();
|
| + if (!writer->WriteBytes(&num_non_retransmiting_packets, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + it = fragment.sent_info.non_retransmiting.begin();
|
| + while (it != fragment.sent_info.non_retransmiting.end()) {
|
| + if (!writer->WriteUInt48(*it)) {
|
| + return false;
|
| + }
|
| + ++it;
|
| + }
|
| +
|
| + if (!writer->WriteBytes(&fragment.congestion_info.type, 1)) {
|
| + return false;
|
| + }
|
| +
|
| + switch (fragment.congestion_info.type) {
|
| + case kNone:
|
| + break;
|
| + case kInterArrival: {
|
| + const CongestionFeedbackMessageInterArrival& inter_arrival =
|
| + fragment.congestion_info.inter_arrival;
|
| + if (!writer->WriteUInt16(
|
| + inter_arrival.accumulated_number_of_lost_packets)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteBytes(&inter_arrival.offset_time, 2)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt16(inter_arrival.delta_time)) {
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + case kFixRate: {
|
| + const CongestionFeedbackMessageFixRate& fix_rate =
|
| + fragment.congestion_info.fix_rate;
|
| + if (!writer->WriteUInt32(fix_rate.bitrate_in_bytes_per_second)) {
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + case kTCP: {
|
| + const CongestionFeedbackMessageTCP& tcp = fragment.congestion_info.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::AppendRstStreamFragmentPayload(
|
| + const QuicRstStreamFragment& fragment,
|
| + QuicDataWriter* writer) {
|
| + if (!writer->WriteUInt32(fragment.stream_id)) {
|
| + return false;
|
| + }
|
| + if (!writer->WriteUInt64(fragment.offset)) {
|
| + return false;
|
| + }
|
| +
|
| + uint32 details = static_cast<uint32>(fragment.details);
|
| + if (!writer->WriteUInt32(details)) {
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool QuicFramer::AppendConnectionCloseFragmentPayload(
|
| + const QuicConnectionCloseFragment& fragment,
|
| + QuicDataWriter* writer) {
|
| + uint32 details = static_cast<uint32>(fragment.details);
|
| + if (!writer->WriteUInt32(details)) {
|
| + return false;
|
| + }
|
| + AppendAckFragmentPayload(fragment.ack_fragment, 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
|
|
|