Index: net/quic/quic_framer.cc |
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc |
index 2ef5c7fbdf1d8390ddc3d1d0e72ffe44a84df42b..c21bd6b72a1a19187e5fbfb9be5a65f846d4d0e6 100644 |
--- a/net/quic/quic_framer.cc |
+++ b/net/quic/quic_framer.cc |
@@ -972,219 +972,224 @@ QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo( |
++iter; |
for (; iter != frame.missing_packets.end(); ++iter) { |
if (cur_range_length != numeric_limits<uint8>::max() && |
- *iter == (last_missing + 1)) { |
- ++cur_range_length; |
- } else { |
- ack_info.nack_ranges[last_missing - cur_range_length] |
- = cur_range_length; |
- cur_range_length = 0; |
+ *iter == (last_missing + 1)) { |
+ ++cur_range_length; |
+ } else { |
+ ack_info.nack_ranges[last_missing - cur_range_length] |
+ = cur_range_length; |
+ cur_range_length = 0; |
+ } |
+ ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing); |
+ last_missing = *iter; |
+ } |
+ // Include the last nack range. |
+ ack_info.nack_ranges[last_missing - cur_range_length] = |
+ cur_range_length; |
+ // Include the range to the largest observed. |
+ ack_info.max_delta = max(ack_info.max_delta, |
+ frame.largest_observed - last_missing); |
} |
- ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing); |
- last_missing = *iter; |
+ return ack_info; |
} |
- // Include the last nack range. |
- ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length; |
- // Include the range to the largest observed. |
- ack_info.max_delta = max(ack_info.max_delta, |
- frame.largest_observed - last_missing); |
- } |
- return ack_info; |
-} |
-bool QuicFramer::ProcessPacketHeader( |
- QuicPacketHeader* header, |
- const QuicEncryptedPacket& packet) { |
- if (!ProcessPacketSequenceNumber(header->public_header.sequence_number_length, |
- &header->packet_sequence_number)) { |
- set_detailed_error("Unable to read sequence number."); |
- return RaiseError(QUIC_INVALID_PACKET_HEADER); |
- } |
+ bool QuicFramer::ProcessPacketHeader( |
+ QuicPacketHeader* header, |
+ const QuicEncryptedPacket& packet) { |
+ if (!ProcessPacketSequenceNumber( |
+ header->public_header.sequence_number_length, |
+ &header->packet_sequence_number)) { |
+ set_detailed_error("Unable to read sequence number."); |
+ return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
- if (header->packet_sequence_number == 0u) { |
- set_detailed_error("Packet sequence numbers cannot be 0."); |
- return RaiseError(QUIC_INVALID_PACKET_HEADER); |
- } |
+ if (header->packet_sequence_number == 0u) { |
+ set_detailed_error("Packet sequence numbers cannot be 0."); |
+ return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
- if (!visitor_->OnUnauthenticatedHeader(*header)) { |
- return false; |
- } |
+ if (!visitor_->OnUnauthenticatedHeader(*header)) { |
+ return false; |
+ } |
- if (!DecryptPayload(*header, packet)) { |
- set_detailed_error("Unable to decrypt payload."); |
- return RaiseError(QUIC_DECRYPTION_FAILURE); |
- } |
+ if (!DecryptPayload(*header, packet)) { |
+ set_detailed_error("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 RaiseError(QUIC_INVALID_PACKET_HEADER); |
- } |
+ uint8 private_flags; |
+ if (!reader_->ReadBytes(&private_flags, 1)) { |
+ set_detailed_error("Unable to read private flags."); |
+ return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
- if (private_flags > PACKET_PRIVATE_FLAGS_MAX) { |
- set_detailed_error("Illegal private flags value."); |
- return RaiseError(QUIC_INVALID_PACKET_HEADER); |
- } |
+ if (private_flags > PACKET_PRIVATE_FLAGS_MAX) { |
+ set_detailed_error("Illegal private flags value."); |
+ return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
- header->entropy_flag = (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0; |
- header->fec_flag = (private_flags & PACKET_PRIVATE_FLAGS_FEC) != 0; |
+ header->entropy_flag = |
+ (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0; |
+ header->fec_flag = (private_flags & PACKET_PRIVATE_FLAGS_FEC) != 0; |
+ |
+ if ((private_flags & PACKET_PRIVATE_FLAGS_FEC_GROUP) != 0) { |
+ header->is_in_fec_group = IN_FEC_GROUP; |
+ 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 RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
+ if (first_fec_protected_packet_offset >= |
+ header->packet_sequence_number) { |
+ set_detailed_error("First fec protected packet offset must be less " |
+ "than the sequence number."); |
+ return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ } |
+ header->fec_group = |
+ header->packet_sequence_number - first_fec_protected_packet_offset; |
+ } |
- if ((private_flags & PACKET_PRIVATE_FLAGS_FEC_GROUP) != 0) { |
- header->is_in_fec_group = IN_FEC_GROUP; |
- 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 RaiseError(QUIC_INVALID_PACKET_HEADER); |
- } |
- if (first_fec_protected_packet_offset >= header->packet_sequence_number) { |
- set_detailed_error("First fec protected packet offset must be less " |
- "than the sequence number."); |
- return RaiseError(QUIC_INVALID_PACKET_HEADER); |
+ header->entropy_hash = GetPacketEntropyHash(*header); |
+ // 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; |
} |
- header->fec_group = |
- header->packet_sequence_number - first_fec_protected_packet_offset; |
- } |
- header->entropy_hash = GetPacketEntropyHash(*header); |
- // 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( |
- QuicSequenceNumberLength sequence_number_length, |
- QuicPacketSequenceNumber* sequence_number) { |
- QuicPacketSequenceNumber wire_sequence_number = 0u; |
- if (!reader_->ReadBytes(&wire_sequence_number, sequence_number_length)) { |
- return false; |
- } |
- |
- // TODO(ianswett): Explore the usefulness of trying multiple sequence numbers |
- // in case the first guess is incorrect. |
- *sequence_number = |
- CalculatePacketSequenceNumberFromWire(sequence_number_length, |
- wire_sequence_number); |
- return true; |
-} |
+ bool QuicFramer::ProcessPacketSequenceNumber( |
+ QuicSequenceNumberLength sequence_number_length, |
+ QuicPacketSequenceNumber* sequence_number) { |
+ QuicPacketSequenceNumber wire_sequence_number = 0u; |
+ if (!reader_->ReadBytes(&wire_sequence_number, sequence_number_length)) { |
+ return false; |
+ } |
-bool QuicFramer::ProcessFrameData(const QuicPacketHeader& header) { |
- if (reader_->IsDoneReading()) { |
- set_detailed_error("Packet has no frames."); |
- return RaiseError(QUIC_MISSING_PAYLOAD); |
- } |
- 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); |
+ // TODO(ianswett): Explore the usefulness of trying multiple sequence |
+ // numbers in case the first guess is incorrect. |
+ *sequence_number = |
+ CalculatePacketSequenceNumberFromWire(sequence_number_length, |
+ wire_sequence_number); |
+ return true; |
} |
- if (frame_type & kQuicFrameTypeSpecialMask) { |
- // Stream Frame |
- if (frame_type & kQuicFrameTypeStreamMask) { |
- QuicStreamFrame frame; |
- if (!ProcessStreamFrame(frame_type, &frame)) { |
- return RaiseError(QUIC_INVALID_STREAM_DATA); |
- } |
- if (!visitor_->OnStreamFrame(frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
- continue; |
+ bool QuicFramer::ProcessFrameData(const QuicPacketHeader& header) { |
+ if (reader_->IsDoneReading()) { |
+ set_detailed_error("Packet has no frames."); |
+ return RaiseError(QUIC_MISSING_PAYLOAD); |
} |
- |
- // Ack Frame |
- if (frame_type & kQuicFrameTypeAckMask) { |
- QuicAckFrame frame; |
- if (!ProcessAckFrame(frame_type, &frame)) { |
- return RaiseError(QUIC_INVALID_ACK_DATA); |
- } |
- if (!visitor_->OnAckFrame(frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
+ 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); |
} |
- continue; |
- } |
- // Congestion Feedback Frame |
- if (frame_type & kQuicFrameTypeCongestionFeedbackMask) { |
- QuicCongestionFeedbackFrame frame; |
- if (!ProcessQuicCongestionFeedbackFrame(&frame)) { |
- return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA); |
- } |
- if (!visitor_->OnCongestionFeedbackFrame(frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
- continue; |
- } |
+ if (frame_type & kQuicFrameTypeSpecialMask) { |
+ // Stream Frame |
+ if (frame_type & kQuicFrameTypeStreamMask) { |
+ QuicStreamFrame frame; |
+ if (!ProcessStreamFrame(frame_type, &frame)) { |
+ return RaiseError(QUIC_INVALID_STREAM_DATA); |
+ } |
+ if (!visitor_->OnStreamFrame(frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- // This was a special frame type that did not match any |
- // of the known ones. Error. |
- set_detailed_error("Illegal frame type."); |
- DLOG(WARNING) << "Illegal frame type: " |
- << static_cast<int>(frame_type); |
- return RaiseError(QUIC_INVALID_FRAME_DATA); |
- } |
+ // Ack Frame |
+ if (frame_type & kQuicFrameTypeAckMask) { |
+ QuicAckFrame frame; |
+ if (!ProcessAckFrame(frame_type, &frame)) { |
+ return RaiseError(QUIC_INVALID_ACK_DATA); |
+ } |
+ if (!visitor_->OnAckFrame(frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- switch (frame_type) { |
- case PADDING_FRAME: |
- // We're done with the packet. |
- return true; |
+ // Congestion Feedback Frame |
+ if (frame_type & kQuicFrameTypeCongestionFeedbackMask) { |
+ QuicCongestionFeedbackFrame frame; |
+ if (!ProcessQuicCongestionFeedbackFrame(&frame)) { |
+ return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA); |
+ } |
+ if (!visitor_->OnCongestionFeedbackFrame(frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- case RST_STREAM_FRAME: { |
- QuicRstStreamFrame frame; |
- if (!ProcessRstStreamFrame(&frame)) { |
- return RaiseError(QUIC_INVALID_RST_STREAM_DATA); |
+ // This was a special frame type that did not match any |
+ // of the known ones. Error. |
+ set_detailed_error("Illegal frame type."); |
+ DLOG(WARNING) << "Illegal frame type: " |
+ << static_cast<int>(frame_type); |
+ return RaiseError(QUIC_INVALID_FRAME_DATA); |
} |
- if (!visitor_->OnRstStreamFrame(frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
- continue; |
- } |
- case CONNECTION_CLOSE_FRAME: { |
- QuicConnectionCloseFrame frame; |
- if (!ProcessConnectionCloseFrame(&frame)) { |
- return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); |
- } |
+ switch (frame_type) { |
+ case PADDING_FRAME: |
+ // We're done with the packet. |
+ return true; |
+ |
+ case RST_STREAM_FRAME: { |
+ QuicRstStreamFrame frame; |
+ if (!ProcessRstStreamFrame(&frame)) { |
+ return RaiseError(QUIC_INVALID_RST_STREAM_DATA); |
+ } |
+ if (!visitor_->OnRstStreamFrame(frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- if (!visitor_->OnConnectionCloseFrame(frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
- continue; |
- } |
+ case CONNECTION_CLOSE_FRAME: { |
+ QuicConnectionCloseFrame frame; |
+ if (!ProcessConnectionCloseFrame(&frame)) { |
+ return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); |
+ } |
+ |
+ if (!visitor_->OnConnectionCloseFrame(frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- case GOAWAY_FRAME: { |
- QuicGoAwayFrame goaway_frame; |
- if (!ProcessGoAwayFrame(&goaway_frame)) { |
- return RaiseError(QUIC_INVALID_GOAWAY_DATA); |
- } |
- if (!visitor_->OnGoAwayFrame(goaway_frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
- continue; |
- } |
+ case GOAWAY_FRAME: { |
+ QuicGoAwayFrame goaway_frame; |
+ if (!ProcessGoAwayFrame(&goaway_frame)) { |
+ return RaiseError(QUIC_INVALID_GOAWAY_DATA); |
+ } |
+ if (!visitor_->OnGoAwayFrame(goaway_frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
+ continue; |
+ } |
- case WINDOW_UPDATE_FRAME: { |
- QuicWindowUpdateFrame window_update_frame; |
- if (!ProcessWindowUpdateFrame(&window_update_frame)) { |
- return RaiseError(QUIC_INVALID_WINDOW_UPDATE_DATA); |
- } |
- if (!visitor_->OnWindowUpdateFrame(window_update_frame)) { |
- DVLOG(1) << "Visitor asked to stop further processing."; |
- // Returning true since there was no parsing error. |
- return true; |
- } |
+ case WINDOW_UPDATE_FRAME: { |
+ QuicWindowUpdateFrame window_update_frame; |
+ if (!ProcessWindowUpdateFrame(&window_update_frame)) { |
+ return RaiseError(QUIC_INVALID_WINDOW_UPDATE_DATA); |
+ } |
+ if (!visitor_->OnWindowUpdateFrame(window_update_frame)) { |
+ DVLOG(1) << "Visitor asked to stop further processing."; |
+ // Returning true since there was no parsing error. |
+ return true; |
+ } |
continue; |
} |
@@ -1417,9 +1422,8 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( |
static_cast<CongestionFeedbackType>(feedback_type); |
switch (frame->type) { |
- case kInterArrival: { |
- CongestionFeedbackMessageInterArrival* inter_arrival = |
- &frame->inter_arrival; |
+ case kTimestamp: { |
+ CongestionFeedbackMessageTimestamp* timestamp = &frame->timestamp; |
uint8 num_received_packets; |
if (!reader_->ReadBytes(&num_received_packets, 1)) { |
set_detailed_error("Unable to read num received packets."); |
@@ -1442,7 +1446,7 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( |
QuicTime time_received = creation_time_.Add( |
QuicTime::Delta::FromMicroseconds(time_received_us)); |
- inter_arrival->received_packet_times.insert( |
+ timestamp->received_packet_times.insert( |
make_pair(smallest_received, time_received)); |
for (uint8 i = 0; i < num_received_packets - 1; ++i) { |
@@ -1460,7 +1464,7 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( |
return false; |
} |
QuicPacketSequenceNumber packet = smallest_received + sequence_delta; |
- inter_arrival->received_packet_times.insert( |
+ timestamp->received_packet_times.insert( |
make_pair(packet, time_received.Add( |
QuicTime::Delta::FromMicroseconds(time_delta_us)))); |
} |
@@ -1469,7 +1473,6 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( |
} |
case kTCP: { |
CongestionFeedbackMessageTCP* tcp = &frame->tcp; |
- // TODO(ianswett): Remove receive window, since it's constant. |
uint16 receive_window = 0; |
if (!reader_->ReadUInt16(&receive_window)) { |
set_detailed_error("Unable to read receive window."); |
@@ -1788,16 +1791,16 @@ size_t QuicFramer::ComputeFrameLength( |
len += 1; // Congestion feedback type. |
switch (congestion_feedback.type) { |
- case kInterArrival: { |
- const CongestionFeedbackMessageInterArrival& inter_arrival = |
- congestion_feedback.inter_arrival; |
+ case kTimestamp: { |
+ const CongestionFeedbackMessageTimestamp& timestamp = |
+ congestion_feedback.timestamp; |
len += 1; // Number received packets. |
- if (inter_arrival.received_packet_times.size() > 0) { |
+ if (!timestamp.received_packet_times.empty()) { |
len += PACKET_6BYTE_SEQUENCE_NUMBER; // Smallest received. |
len += 8; // Time. |
// 2 bytes per sequence number delta plus 4 bytes per delta time. |
len += PACKET_6BYTE_SEQUENCE_NUMBER * |
- (inter_arrival.received_packet_times.size() - 1); |
+ (timestamp.received_packet_times.size() - 1); |
} |
break; |
} |
@@ -2094,55 +2097,8 @@ bool QuicFramer::AppendCongestionFeedbackFrame( |
} |
switch (frame.type) { |
- case kInterArrival: { |
- const CongestionFeedbackMessageInterArrival& inter_arrival = |
- frame.inter_arrival; |
- 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(PACKET_6BYTE_SEQUENCE_NUMBER, |
- lowest_sequence, writer)) { |
- return false; |
- } |
- |
- QuicTime lowest_time = it->second; |
- if (!writer->WriteUInt64( |
- lowest_time.Subtract(creation_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 kTimestamp: { |
+ return AppendTimestampFrame(frame, writer); |
} |
case kTCP: { |
const CongestionFeedbackMessageTCP& tcp = frame.tcp; |
@@ -2161,6 +2117,53 @@ bool QuicFramer::AppendCongestionFeedbackFrame( |
return true; |
} |
+bool QuicFramer::AppendTimestampFrame( |
+ const QuicCongestionFeedbackFrame& frame, |
+ QuicDataWriter* writer) { |
+ const CongestionFeedbackMessageTimestamp& timestamp = frame.timestamp; |
+ DCHECK_GE(numeric_limits<uint8>::max(), |
+ timestamp.received_packet_times.size()); |
+ if (timestamp.received_packet_times.size() > numeric_limits<uint8>::max()) { |
+ return false; |
+ } |
+ uint8 num_received_packets = timestamp.received_packet_times.size(); |
+ if (!writer->WriteBytes(&num_received_packets, 1)) { |
+ return false; |
+ } |
+ if (num_received_packets > 0) { |
+ TimeMap::const_iterator it = timestamp.received_packet_times.begin(); |
+ |
+ QuicPacketSequenceNumber lowest_sequence = it->first; |
+ if (!AppendPacketSequenceNumber(PACKET_6BYTE_SEQUENCE_NUMBER, |
+ lowest_sequence, writer)) { |
+ return false; |
+ } |
+ |
+ QuicTime lowest_time = it->second; |
+ if (!writer->WriteUInt64( |
+ lowest_time.Subtract(creation_time_).ToMicroseconds())) { |
+ return false; |
+ } |
+ |
+ for (++it; it != timestamp.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; |
+ } |
+ } |
+ } |
+ return true; |
+} |
+ |
bool QuicFramer::AppendStopWaitingFrame( |
const QuicPacketHeader& header, |
const QuicStopWaitingFrame& frame, |