![]() |
VOOZH | about |
| OLD | NEW |
|---|---|
| (Empty) | |
| // 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 | |
|
jar (doing other things)
2012/10/14 23:04:38
nit: comments start with Upper-case, and end with
Ryan Hamilton
2012/10/15 21:22:08
Done.
| |
| size_t len = kPacketHeaderSize; | |
| len += 1; // fragment count | |
|
jar (doing other things)
2012/10/14 23:04:38
nit: IMO, nicer would be sizeof(some_named_member_
Ryan Hamilton
2012/10/15 21:22:08
That's a bit tricky because the sizeof(member_) is
| |
| 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 | |
| if (!writer.WriteUInt8(fragments.size())) { | |
|
jar (doing other things)
2012/10/14 23:04:38
Do we have guarantees that framents.size() is less
Ryan Hamilton
2012/10/15 21:22:08
Added DCHECK
| |
| 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 | |
| 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) { | |
| DCHECK_GT(packet->length(), kPacketHeaderSize); | |
|
jar (doing other things)
2012/10/14 23:04:38
A CHECK is a bit tempting here. I'm not sure abou
Ryan Hamilton
2012/10/15 21:22:08
In general we really don't want the server to cras
jar (doing other things)
2012/10/15 23:54:32
It sure seems evil to increment memory that is not
Ryan Hamilton
2012/10/16 00:03:56
Done. I'll attempt to land a CHECK on the server
| |
| ++packet->mutable_data()[kRetransmissionOffset]; | |
| } | |
| uint8 QuicFramer::GetRetransmitCount(QuicPacket* packet) { | |
| DCHECK_GT(packet->length(), kPacketHeaderSize); | |
| return packet->mutable_data()[kRetransmissionOffset]; | |
| } | |
| bool QuicFramer::ProcessPacket(const IPEndPoint& peer_address, | |
| const QuicEncryptedPacket& packet) { | |
| LOG(INFO) << "here!"; | |
|
jar (doing other things)
2012/10/14 23:04:38
nit: DLOG
Ryan Hamilton
2012/10/15 21:22:08
Removed.
| |
| 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); | |
|
jar (doing other things)
2012/10/14 23:04:38
I wasn't clear about when you wanted to delete rea
Ryan Hamilton
2012/10/15 21:22:08
I believe it is dropped everywhere. Note the DCHE
jar (doing other things)
2012/10/15 23:54:32
There are a bunch of early returns that don't *see
Ryan Hamilton
2012/10/16 00:03:56
You're talking about this, right:
158 retur
Ryan Hamilton
2012/10/16 16:46:47
Looks like 166 and 177 do not RaiseError. I'll fi
| |
| 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."; | |
|
jar (doing other things)
2012/10/14 23:04:38
This appears to be the only path where reader_ is
Ryan Hamilton
2012/10/15 21:22:08
I believe it is dropped here because RaiseError is
| |
| 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) { | |
| LOG(INFO) << "here!"; | |
| // ConnectionHeader | |
| if (!reader_->ReadUInt64(&header->guid)) { | |
| set_detailed_error("Unable to read GUID."); | |
| return false; | |
| } | |
| LOG(INFO) << "here!"; | |
| if (!reader_->ReadUInt48(&header->packet_sequence_number)) { | |
| set_detailed_error("Unable to read sequence number."); | |
| return false; | |
| } | |
| LOG(INFO) << "here!"; | |
| if (!reader_->ReadBytes(&header->retransmission_count, 1)) { | |
| set_detailed_error("Unable to read retransmission count."); | |
| return false; | |
| } | |
| // CongestionMonitoredHeader | |
| LOG(INFO) << "here!"; | |
| if (!reader_->ReadUInt64(&header->transmission_time)) { | |
| set_detailed_error("Unable to read transmission time."); | |
| return false; | |
| } | |
| unsigned char flags; | |
| LOG(INFO) << "here!"; | |
| if (!reader_->ReadBytes(&flags, 1)) { | |
| set_detailed_error("Unable to read flags."); | |
| return false; | |
| } | |
| LOG(INFO) << "here!"; | |
| if (flags > PACKET_FLAGS_MAX) { | |
| set_detailed_error("Illegal flags value."); | |
| return false; | |
| } | |
| LOG(INFO) << "here!"; | |
| header->flags = static_cast<QuicPacketFlags>(flags); | |
| LOG(INFO) << "here!"; | |
| if (!DecryptPayload(packet)) { | |
| DLOG(WARNING) << "Unable to decrypt payload."; | |
| return RaiseError(QUIC_DECRYPTION_FAILURE); | |
| } | |
| LOG(INFO) << "here!"; | |
| if (!reader_->ReadBytes(&header->fec_group, 1)) { | |
| set_detailed_error("Unable to read fec group."); | |
| return false; | |
| } | |
| LOG(INFO) << "done!"; | |
| 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) { | |
| return false; | |
|
jar (doing other things)
2012/10/14 23:04:38
nit: perhaps set detailed error?
Ryan Hamilton
2012/10/15 21:22:08
Done. I assume this code path will change at some
| |
| } | |
| 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) { | |
| LOG(INFO) << "here!"; | |
| StringPiece encrypted; | |
| if (!reader_->ReadStringPiece(&encrypted, reader_->BytesRemaining())) { | |
| return false; | |
| } | |
| DCHECK(decrypter_.get() != NULL); | |
| LOG(INFO) << "here!"; | |
| 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; | |
| switch (fragment.type) { | |
| case STREAM_FRAGMENT: | |
| len += 4; // stream id | |
|
jar (doing other things)
2012/10/14 23:04:38
nit: IMO, much better would be mostly sizeof(named
Ryan Hamilton
2012/10/15 21:22:08
This is not guaranteed to work because the in-memo
| |
| 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 | |
| OLD | NEW |