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