xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/simulator/quic_endpoint_base.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_base.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "absl/strings/str_cat.h"
11 #include "quiche/quic/core/crypto/crypto_handshake_message.h"
12 #include "quiche/quic/core/crypto/crypto_protocol.h"
13 #include "quiche/quic/core/quic_connection.h"
14 #include "quiche/quic/core/quic_data_writer.h"
15 #include "quiche/quic/platform/api/quic_test_output.h"
16 #include "quiche/quic/test_tools/quic_connection_peer.h"
17 #include "quiche/quic/test_tools/quic_test_utils.h"
18 #include "quiche/quic/test_tools/simulator/simulator.h"
19 
20 namespace quic {
21 namespace simulator {
22 
23 // Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
HashNameIntoFive32BitIntegers(std::string name)24 static std::vector<uint32_t> HashNameIntoFive32BitIntegers(std::string name) {
25   const std::string hash = test::Sha1Hash(name);
26 
27   std::vector<uint32_t> output;
28   uint32_t current_number = 0;
29   for (size_t i = 0; i < hash.size(); i++) {
30     current_number = (current_number << 8) + hash[i];
31     if (i % 4 == 3) {
32       output.push_back(i);
33       current_number = 0;
34     }
35   }
36 
37   return output;
38 }
39 
GetAddressFromName(std::string name)40 QuicSocketAddress GetAddressFromName(std::string name) {
41   const std::vector<uint32_t> hash = HashNameIntoFive32BitIntegers(name);
42 
43   // Generate a random port between 1025 and 65535.
44   const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1);
45 
46   // Generate a random 10.x.x.x address, where x is between 1 and 254.
47   std::string ip_address{"\xa\0\0\0", 4};
48   for (size_t i = 1; i < 4; i++) {
49     ip_address[i] = 1 + hash[i] % 254;
50   }
51   QuicIpAddress host;
52   host.FromPackedString(ip_address.c_str(), ip_address.length());
53   return QuicSocketAddress(host, port);
54 }
55 
QuicEndpointBase(Simulator * simulator,std::string name,std::string peer_name)56 QuicEndpointBase::QuicEndpointBase(Simulator* simulator, std::string name,
57                                    std::string peer_name)
58     : Endpoint(simulator, name),
59       peer_name_(peer_name),
60       writer_(this),
61       nic_tx_queue_(simulator, absl::StrCat(name, " (TX Queue)"),
62                     kMaxOutgoingPacketSize * kTxQueueSize),
63       connection_(nullptr),
64       write_blocked_count_(0),
65       drop_next_packet_(false) {
66   nic_tx_queue_.set_listener_interface(this);
67 }
68 
~QuicEndpointBase()69 QuicEndpointBase::~QuicEndpointBase() {
70   if (trace_visitor_ != nullptr) {
71     const char* perspective_prefix =
72         connection_->perspective() == Perspective::IS_CLIENT ? "C" : "S";
73 
74     std::string identifier = absl::StrCat(
75         perspective_prefix, connection_->connection_id().ToString());
76     QuicRecordTrace(identifier, trace_visitor_->trace()->SerializeAsString());
77   }
78 }
79 
DropNextIncomingPacket()80 void QuicEndpointBase::DropNextIncomingPacket() { drop_next_packet_ = true; }
81 
RecordTrace()82 void QuicEndpointBase::RecordTrace() {
83   trace_visitor_ = std::make_unique<QuicTraceVisitor>(connection_.get());
84   connection_->set_debug_visitor(trace_visitor_.get());
85 }
86 
AcceptPacket(std::unique_ptr<Packet> packet)87 void QuicEndpointBase::AcceptPacket(std::unique_ptr<Packet> packet) {
88   if (packet->destination != name_) {
89     return;
90   }
91   if (drop_next_packet_) {
92     drop_next_packet_ = false;
93     return;
94   }
95 
96   QuicReceivedPacket received_packet(packet->contents.data(),
97                                      packet->contents.size(), clock_->Now());
98   connection_->ProcessUdpPacket(connection_->self_address(),
99                                 connection_->peer_address(), received_packet);
100 }
101 
GetRxPort()102 UnconstrainedPortInterface* QuicEndpointBase::GetRxPort() { return this; }
103 
SetTxPort(ConstrainedPortInterface * port)104 void QuicEndpointBase::SetTxPort(ConstrainedPortInterface* port) {
105   // Any egress done by the endpoint is actually handled by a queue on an NIC.
106   nic_tx_queue_.set_tx_port(port);
107 }
108 
OnPacketDequeued()109 void QuicEndpointBase::OnPacketDequeued() {
110   if (writer_.IsWriteBlocked() &&
111       (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
112           kMaxOutgoingPacketSize) {
113     writer_.SetWritable();
114     connection_->OnCanWrite();
115   }
116 }
117 
Writer(QuicEndpointBase * endpoint)118 QuicEndpointBase::Writer::Writer(QuicEndpointBase* endpoint)
119     : endpoint_(endpoint), is_blocked_(false) {}
120 
~Writer()121 QuicEndpointBase::Writer::~Writer() {}
122 
WritePacket(const char * buffer,size_t buf_len,const QuicIpAddress &,const QuicSocketAddress &,PerPacketOptions * options,const QuicPacketWriterParams &)123 WriteResult QuicEndpointBase::Writer::WritePacket(
124     const char* buffer, size_t buf_len, const QuicIpAddress& /*self_address*/,
125     const QuicSocketAddress& /*peer_address*/, PerPacketOptions* options,
126     const QuicPacketWriterParams& /*params*/) {
127   QUICHE_DCHECK(!IsWriteBlocked());
128   QUICHE_DCHECK(options == nullptr);
129   QUICHE_DCHECK(buf_len <= kMaxOutgoingPacketSize);
130 
131   // Instead of losing a packet, become write-blocked when the egress queue is
132   // full.
133   if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
134     is_blocked_ = true;
135     endpoint_->write_blocked_count_++;
136     return WriteResult(WRITE_STATUS_BLOCKED, 0);
137   }
138 
139   auto packet = std::make_unique<Packet>();
140   packet->source = endpoint_->name();
141   packet->destination = endpoint_->peer_name_;
142   packet->tx_timestamp = endpoint_->clock_->Now();
143 
144   packet->contents = std::string(buffer, buf_len);
145   packet->size = buf_len;
146 
147   endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet));
148 
149   return WriteResult(WRITE_STATUS_OK, buf_len);
150 }
151 
IsWriteBlocked() const152 bool QuicEndpointBase::Writer::IsWriteBlocked() const { return is_blocked_; }
153 
SetWritable()154 void QuicEndpointBase::Writer::SetWritable() { is_blocked_ = false; }
155 
MessageTooBigErrorCode() const156 std::optional<int> QuicEndpointBase::Writer::MessageTooBigErrorCode() const {
157   return std::nullopt;
158 }
159 
GetMaxPacketSize(const QuicSocketAddress &) const160 QuicByteCount QuicEndpointBase::Writer::GetMaxPacketSize(
161     const QuicSocketAddress& /*peer_address*/) const {
162   return kMaxOutgoingPacketSize;
163 }
164 
SupportsReleaseTime() const165 bool QuicEndpointBase::Writer::SupportsReleaseTime() const { return false; }
166 
IsBatchMode() const167 bool QuicEndpointBase::Writer::IsBatchMode() const { return false; }
168 
GetNextWriteLocation(const QuicIpAddress &,const QuicSocketAddress &)169 QuicPacketBuffer QuicEndpointBase::Writer::GetNextWriteLocation(
170     const QuicIpAddress& /*self_address*/,
171     const QuicSocketAddress& /*peer_address*/) {
172   return {nullptr, nullptr};
173 }
174 
Flush()175 WriteResult QuicEndpointBase::Writer::Flush() {
176   return WriteResult(WRITE_STATUS_OK, 0);
177 }
178 
QuicEndpointMultiplexer(std::string name,const std::vector<QuicEndpointBase * > & endpoints)179 QuicEndpointMultiplexer::QuicEndpointMultiplexer(
180     std::string name, const std::vector<QuicEndpointBase*>& endpoints)
181     : Endpoint((*endpoints.begin())->simulator(), name) {
182   for (QuicEndpointBase* endpoint : endpoints) {
183     mapping_.insert(std::make_pair(endpoint->name(), endpoint));
184   }
185 }
186 
~QuicEndpointMultiplexer()187 QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {}
188 
AcceptPacket(std::unique_ptr<Packet> packet)189 void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr<Packet> packet) {
190   auto key_value_pair_it = mapping_.find(packet->destination);
191   if (key_value_pair_it == mapping_.end()) {
192     return;
193   }
194 
195   key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet));
196 }
GetRxPort()197 UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() {
198   return this;
199 }
SetTxPort(ConstrainedPortInterface * port)200 void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) {
201   for (auto& key_value_pair : mapping_) {
202     key_value_pair.second->SetTxPort(port);
203   }
204 }
205 
206 }  // namespace simulator
207 }  // namespace quic
208