xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2012 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/test_tools/simulator/quic_endpoint.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "quiche/quic/core/crypto/crypto_handshake_message.h"
11 #include "quiche/quic/core/crypto/crypto_protocol.h"
12 #include "quiche/quic/core/quic_data_writer.h"
13 #include "quiche/quic/platform/api/quic_test_output.h"
14 #include "quiche/quic/test_tools/quic_config_peer.h"
15 #include "quiche/quic/test_tools/quic_connection_peer.h"
16 #include "quiche/quic/test_tools/quic_test_utils.h"
17 #include "quiche/quic/test_tools/simulator/simulator.h"
18 
19 namespace quic {
20 namespace simulator {
21 
22 const QuicStreamId kDataStream = 3;
23 const QuicByteCount kWriteChunkSize = 128 * 1024;
24 const char kStreamDataContents = 'Q';
25 
QuicEndpoint(Simulator * simulator,std::string name,std::string peer_name,Perspective perspective,QuicConnectionId connection_id)26 QuicEndpoint::QuicEndpoint(Simulator* simulator, std::string name,
27                            std::string peer_name, Perspective perspective,
28                            QuicConnectionId connection_id)
29     : QuicEndpointBase(simulator, name, peer_name),
30       bytes_to_transfer_(0),
31       bytes_transferred_(0),
32       wrong_data_received_(false),
33       notifier_(nullptr) {
34   connection_ = std::make_unique<QuicConnection>(
35       connection_id, GetAddressFromName(name), GetAddressFromName(peer_name),
36       simulator, simulator->GetAlarmFactory(), &writer_, false, perspective,
37       ParsedVersionOfIndex(CurrentSupportedVersions(), 0),
38       connection_id_generator_);
39   connection_->set_visitor(this);
40   connection_->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
41                             std::make_unique<quic::test::TaggingEncrypter>(
42                                 ENCRYPTION_FORWARD_SECURE));
43   connection_->SetEncrypter(ENCRYPTION_INITIAL, nullptr);
44   if (connection_->version().KnowsWhichDecrypterToUse()) {
45     connection_->InstallDecrypter(
46         ENCRYPTION_FORWARD_SECURE,
47         std::make_unique<quic::test::StrictTaggingDecrypter>(
48             ENCRYPTION_FORWARD_SECURE));
49     connection_->RemoveDecrypter(ENCRYPTION_INITIAL);
50   } else {
51     connection_->SetDecrypter(
52         ENCRYPTION_FORWARD_SECURE,
53         std::make_unique<quic::test::StrictTaggingDecrypter>(
54             ENCRYPTION_FORWARD_SECURE));
55   }
56   connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
57   connection_->OnHandshakeComplete();
58   if (perspective == Perspective::IS_SERVER) {
59     // Skip version negotiation.
60     test::QuicConnectionPeer::SetNegotiatedVersion(connection_.get());
61   }
62   test::QuicConnectionPeer::SetAddressValidated(connection_.get());
63   connection_->SetDataProducer(&producer_);
64   connection_->SetSessionNotifier(this);
65   notifier_ = std::make_unique<test::SimpleSessionNotifier>(connection_.get());
66 
67   // Configure the connection as if it received a handshake.  This is important
68   // primarily because
69   //  - this enables pacing, and
70   //  - this sets the non-handshake timeouts.
71   std::string error;
72   CryptoHandshakeMessage peer_hello;
73   peer_hello.SetValue(kICSL,
74                       static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1));
75   peer_hello.SetValue(kMIBS,
76                       static_cast<uint32_t>(kDefaultMaxStreamsPerConnection));
77   QuicConfig config;
78   QuicErrorCode error_code = config.ProcessPeerHello(
79       peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
80       &error);
81   QUICHE_DCHECK_EQ(error_code, QUIC_NO_ERROR)
82       << "Configuration failed: " << error;
83   if (connection_->version().UsesTls()) {
84     if (connection_->perspective() == Perspective::IS_CLIENT) {
85       test::QuicConfigPeer::SetReceivedOriginalConnectionId(
86           &config, connection_->connection_id());
87       test::QuicConfigPeer::SetReceivedInitialSourceConnectionId(
88           &config, connection_->connection_id());
89     } else {
90       test::QuicConfigPeer::SetReceivedInitialSourceConnectionId(
91           &config, connection_->client_connection_id());
92     }
93   }
94   connection_->SetFromConfig(config);
95   connection_->DisableMtuDiscovery();
96 }
97 
bytes_received() const98 QuicByteCount QuicEndpoint::bytes_received() const {
99   QuicByteCount total = 0;
100   for (auto& interval : offsets_received_) {
101     total += interval.max() - interval.min();
102   }
103   return total;
104 }
105 
bytes_to_transfer() const106 QuicByteCount QuicEndpoint::bytes_to_transfer() const {
107   if (notifier_ != nullptr) {
108     return notifier_->StreamBytesToSend();
109   }
110   return bytes_to_transfer_;
111 }
112 
bytes_transferred() const113 QuicByteCount QuicEndpoint::bytes_transferred() const {
114   if (notifier_ != nullptr) {
115     return notifier_->StreamBytesSent();
116   }
117   return bytes_transferred_;
118 }
119 
AddBytesToTransfer(QuicByteCount bytes)120 void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) {
121   if (notifier_ != nullptr) {
122     if (notifier_->HasBufferedStreamData()) {
123       Schedule(clock_->Now());
124     }
125     notifier_->WriteOrBufferData(kDataStream, bytes, NO_FIN);
126     return;
127   }
128 
129   if (bytes_to_transfer_ > 0) {
130     Schedule(clock_->Now());
131   }
132 
133   bytes_to_transfer_ += bytes;
134   WriteStreamData();
135 }
136 
OnStreamFrame(const QuicStreamFrame & frame)137 void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) {
138   // Verify that the data received always matches the expected.
139   QUICHE_DCHECK(frame.stream_id == kDataStream);
140   for (size_t i = 0; i < frame.data_length; i++) {
141     if (frame.data_buffer[i] != kStreamDataContents) {
142       wrong_data_received_ = true;
143     }
144   }
145   offsets_received_.Add(frame.offset, frame.offset + frame.data_length);
146   // Sanity check against very pathological connections.
147   QUICHE_DCHECK_LE(offsets_received_.Size(), 1000u);
148 }
149 
OnCryptoFrame(const QuicCryptoFrame &)150 void QuicEndpoint::OnCryptoFrame(const QuicCryptoFrame& /*frame*/) {}
151 
OnCanWrite()152 void QuicEndpoint::OnCanWrite() {
153   if (notifier_ != nullptr) {
154     notifier_->OnCanWrite();
155     return;
156   }
157   WriteStreamData();
158 }
159 
WillingAndAbleToWrite() const160 bool QuicEndpoint::WillingAndAbleToWrite() const {
161   if (notifier_ != nullptr) {
162     return notifier_->WillingToWrite();
163   }
164   return bytes_to_transfer_ != 0;
165 }
ShouldKeepConnectionAlive() const166 bool QuicEndpoint::ShouldKeepConnectionAlive() const { return true; }
167 
AllowSelfAddressChange() const168 bool QuicEndpoint::AllowSelfAddressChange() const { return false; }
169 
OnFrameAcked(const QuicFrame & frame,QuicTime::Delta ack_delay_time,QuicTime receive_timestamp)170 bool QuicEndpoint::OnFrameAcked(const QuicFrame& frame,
171                                 QuicTime::Delta ack_delay_time,
172                                 QuicTime receive_timestamp) {
173   if (notifier_ != nullptr) {
174     return notifier_->OnFrameAcked(frame, ack_delay_time, receive_timestamp);
175   }
176   return false;
177 }
178 
OnFrameLost(const QuicFrame & frame)179 void QuicEndpoint::OnFrameLost(const QuicFrame& frame) {
180   QUICHE_DCHECK(notifier_);
181   notifier_->OnFrameLost(frame);
182 }
183 
RetransmitFrames(const QuicFrames & frames,TransmissionType type)184 bool QuicEndpoint::RetransmitFrames(const QuicFrames& frames,
185                                     TransmissionType type) {
186   QUICHE_DCHECK(notifier_);
187   return notifier_->RetransmitFrames(frames, type);
188 }
189 
IsFrameOutstanding(const QuicFrame & frame) const190 bool QuicEndpoint::IsFrameOutstanding(const QuicFrame& frame) const {
191   QUICHE_DCHECK(notifier_);
192   return notifier_->IsFrameOutstanding(frame);
193 }
194 
HasUnackedCryptoData() const195 bool QuicEndpoint::HasUnackedCryptoData() const { return false; }
196 
HasUnackedStreamData() const197 bool QuicEndpoint::HasUnackedStreamData() const {
198   if (notifier_ != nullptr) {
199     return notifier_->HasUnackedStreamData();
200   }
201   return false;
202 }
203 
GetHandshakeState() const204 HandshakeState QuicEndpoint::GetHandshakeState() const {
205   return HANDSHAKE_COMPLETE;
206 }
207 
WriteStreamData(QuicStreamId,QuicStreamOffset,QuicByteCount data_length,QuicDataWriter * writer)208 WriteStreamDataResult QuicEndpoint::DataProducer::WriteStreamData(
209     QuicStreamId /*id*/, QuicStreamOffset /*offset*/, QuicByteCount data_length,
210     QuicDataWriter* writer) {
211   writer->WriteRepeatedByte(kStreamDataContents, data_length);
212   return WRITE_SUCCESS;
213 }
214 
WriteCryptoData(EncryptionLevel,QuicStreamOffset,QuicByteCount,QuicDataWriter *)215 bool QuicEndpoint::DataProducer::WriteCryptoData(EncryptionLevel /*level*/,
216                                                  QuicStreamOffset /*offset*/,
217                                                  QuicByteCount /*data_length*/,
218                                                  QuicDataWriter* /*writer*/) {
219   QUIC_BUG(quic_bug_10157_1)
220       << "QuicEndpoint::DataProducer::WriteCryptoData is unimplemented";
221   return false;
222 }
223 
WriteStreamData()224 void QuicEndpoint::WriteStreamData() {
225   // Instantiate a flusher which would normally be here due to QuicSession.
226   QuicConnection::ScopedPacketFlusher flusher(connection_.get());
227 
228   while (bytes_to_transfer_ > 0) {
229     // Transfer data in chunks of size at most |kWriteChunkSize|.
230     const size_t transmission_size =
231         std::min(kWriteChunkSize, bytes_to_transfer_);
232 
233     QuicConsumedData consumed_data = connection_->SendStreamData(
234         kDataStream, transmission_size, bytes_transferred_, NO_FIN);
235 
236     QUICHE_DCHECK(consumed_data.bytes_consumed <= transmission_size);
237     bytes_transferred_ += consumed_data.bytes_consumed;
238     bytes_to_transfer_ -= consumed_data.bytes_consumed;
239     if (consumed_data.bytes_consumed != transmission_size) {
240       return;
241     }
242   }
243 }
244 
245 }  // namespace simulator
246 }  // namespace quic
247