xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/tools/quic_tcp_like_trace_converter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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