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