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