1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/tools/quic_tcp_like_trace_converter.h"
6
7 #include "quiche/quic/core/quic_constants.h"
8 #include "quiche/quic/platform/api/quic_bug_tracker.h"
9
10 namespace quic {
11
QuicTcpLikeTraceConverter()12 QuicTcpLikeTraceConverter::QuicTcpLikeTraceConverter()
13 : largest_observed_control_frame_id_(kInvalidControlFrameId),
14 connection_offset_(0) {}
15
StreamOffsetSegment()16 QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment()
17 : connection_offset(0) {}
18
StreamOffsetSegment(QuicStreamOffset stream_offset,uint64_t connection_offset,QuicByteCount data_length)19 QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment(
20 QuicStreamOffset stream_offset, uint64_t connection_offset,
21 QuicByteCount data_length)
22 : stream_data(stream_offset, stream_offset + data_length),
23 connection_offset(connection_offset) {}
24
StreamInfo()25 QuicTcpLikeTraceConverter::StreamInfo::StreamInfo() : fin(false) {}
26
OnCryptoFrameSent(EncryptionLevel level,QuicStreamOffset offset,QuicByteCount data_length)27 QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnCryptoFrameSent(
28 EncryptionLevel level, QuicStreamOffset offset, QuicByteCount data_length) {
29 if (level >= NUM_ENCRYPTION_LEVELS) {
30 QUIC_BUG(quic_bug_10907_1) << "Invalid encryption level";
31 return {};
32 }
33 return OnFrameSent(offset, data_length, /*fin=*/false,
34 &crypto_frames_info_[level]);
35 }
36
OnStreamFrameSent(QuicStreamId stream_id,QuicStreamOffset offset,QuicByteCount data_length,bool fin)37 QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent(
38 QuicStreamId stream_id, QuicStreamOffset offset, QuicByteCount data_length,
39 bool fin) {
40 return OnFrameSent(
41 offset, data_length, fin,
42 &streams_info_.emplace(stream_id, StreamInfo()).first->second);
43 }
44
OnFrameSent(QuicStreamOffset offset,QuicByteCount data_length,bool fin,StreamInfo * info)45 QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnFrameSent(
46 QuicStreamOffset offset, QuicByteCount data_length, bool fin,
47 StreamInfo* info) {
48 QuicIntervalSet<uint64_t> connection_offsets;
49 if (fin) {
50 // Stream fin consumes a connection offset.
51 ++data_length;
52 }
53 // Get connection offsets of retransmission data in this frame.
54 for (const auto& segment : info->segments) {
55 QuicInterval<QuicStreamOffset> retransmission(offset, offset + data_length);
56 retransmission.IntersectWith(segment.stream_data);
57 if (retransmission.Empty()) {
58 continue;
59 }
60 const uint64_t connection_offset = segment.connection_offset +
61 retransmission.min() -
62 segment.stream_data.min();
63 connection_offsets.Add(connection_offset,
64 connection_offset + retransmission.Length());
65 }
66
67 if (info->fin) {
68 return connection_offsets;
69 }
70
71 // Get connection offsets of new data in this frame.
72 QuicStreamOffset least_unsent_offset =
73 info->segments.empty() ? 0 : info->segments.back().stream_data.max();
74 if (least_unsent_offset >= offset + data_length) {
75 return connection_offsets;
76 }
77 // Ignore out-of-order stream data so that as connection offset increases,
78 // stream offset increases.
79 QuicStreamOffset new_data_offset = std::max(least_unsent_offset, offset);
80 QuicByteCount new_data_length = offset + data_length - new_data_offset;
81 connection_offsets.Add(connection_offset_,
82 connection_offset_ + new_data_length);
83 if (!info->segments.empty() && new_data_offset == least_unsent_offset &&
84 connection_offset_ == info->segments.back().connection_offset +
85 info->segments.back().stream_data.Length()) {
86 // Extend the last segment if both stream and connection offsets are
87 // contiguous.
88 info->segments.back().stream_data.SetMax(new_data_offset + new_data_length);
89 } else {
90 info->segments.emplace_back(new_data_offset, connection_offset_,
91 new_data_length);
92 }
93 info->fin = fin;
94 connection_offset_ += new_data_length;
95
96 return connection_offsets;
97 }
98
OnControlFrameSent(QuicControlFrameId control_frame_id,QuicByteCount control_frame_length)99 QuicInterval<uint64_t> QuicTcpLikeTraceConverter::OnControlFrameSent(
100 QuicControlFrameId control_frame_id, QuicByteCount control_frame_length) {
101 if (control_frame_id > largest_observed_control_frame_id_) {
102 // New control frame.
103 QuicInterval<uint64_t> connection_offset = QuicInterval<uint64_t>(
104 connection_offset_, connection_offset_ + control_frame_length);
105 connection_offset_ += control_frame_length;
106 control_frames_info_[control_frame_id] = connection_offset;
107 largest_observed_control_frame_id_ = control_frame_id;
108 return connection_offset;
109 }
110 const auto iter = control_frames_info_.find(control_frame_id);
111 if (iter == control_frames_info_.end()) {
112 // Ignore out of order control frames.
113 return {};
114 }
115 return iter->second;
116 }
117
118 } // namespace quic
119