blob: 3301ef5d01415637607d68bb4e0d070a50c4440b [file] [log] [blame]
// Copyright (c) 2018 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/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
namespace quic {
QuicTcpLikeTraceConverter::QuicTcpLikeTraceConverter()
: largest_observed_control_frame_id_(kInvalidControlFrameId),
connection_offset_(0) {}
QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment()
: connection_offset(0) {}
QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment(
QuicStreamOffset stream_offset,
uint64_t connection_offset,
QuicByteCount data_length)
: stream_data(stream_offset, stream_offset + data_length),
connection_offset(connection_offset) {}
QuicTcpLikeTraceConverter::StreamInfo::StreamInfo() : fin(false) {}
QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
QuicStreamId stream_id,
QuicStreamOffset offset,
QuicByteCount data_length,
bool fin) {
QuicIntervalSet<uint64_t> connection_offsets;
if (fin) {
// Stream fin consumes a connection offset.
++data_length;
}
StreamInfo* stream_info =
&streams_info_.emplace(stream_id, StreamInfo()).first->second;
// Get connection offsets of retransmission data in this frame.
for (const auto& segment : stream_info->segments) {
QuicInterval<QuicStreamOffset> retransmission(offset, offset + data_length);
retransmission.IntersectWith(segment.stream_data);
if (retransmission.Empty()) {
continue;
}
const uint64_t connection_offset = segment.connection_offset +
retransmission.min() -
segment.stream_data.min();
connection_offsets.Add(connection_offset,
connection_offset + retransmission.Length());
}
if (stream_info->fin) {
return connection_offsets;
}
// Get connection offsets of new data in this frame.
QuicStreamOffset least_unsent_offset =
stream_info->segments.empty()
? 0
: stream_info->segments.back().stream_data.max();
if (least_unsent_offset >= offset + data_length) {
return connection_offsets;
}
// Ignore out-of-order stream data so that as connection offset increases,
// stream offset increases.
QuicStreamOffset new_data_offset = std::max(least_unsent_offset, offset);
QuicByteCount new_data_length = offset + data_length - new_data_offset;
connection_offsets.Add(connection_offset_,
connection_offset_ + new_data_length);
if (!stream_info->segments.empty() &&
new_data_offset == least_unsent_offset &&
connection_offset_ ==
stream_info->segments.back().connection_offset +
stream_info->segments.back().stream_data.Length()) {
// Extend the last segment if both stream and connection offsets are
// contiguous.
stream_info->segments.back().stream_data.SetMax(new_data_offset +
new_data_length);
} else {
stream_info->segments.emplace_back(new_data_offset, connection_offset_,
new_data_length);
}
stream_info->fin = fin;
connection_offset_ += new_data_length;
return connection_offsets;
}
QuicInterval<uint64_t> QuicTcpLikeTraceConverter::OnControlFrameSent(
QuicControlFrameId control_frame_id,
QuicByteCount control_frame_length) {
if (control_frame_id > largest_observed_control_frame_id_) {
// New control frame.
QuicInterval<uint64_t> connection_offset = QuicInterval<uint64_t>(
connection_offset_, connection_offset_ + control_frame_length);
connection_offset_ += control_frame_length;
control_frames_info_[control_frame_id] = connection_offset;
largest_observed_control_frame_id_ = control_frame_id;
return connection_offset;
}
const auto iter = control_frames_info_.find(control_frame_id);
if (iter == control_frames_info_.end()) {
// Ignore out of order control frames.
return {};
}
return iter->second;
}
} // namespace quic