Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(890)

Side by Side Diff: net/quic/core/congestion_control/simulation/quic_endpoint.cc

Issue 2322233004: Landing Recent QUIC changes until Sun Sep 4 03:41:00 (Closed)
Patch Set: Remove simulation files from the build. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "base/memory/ptr_util.h"
6 #include "base/sha1.h"
7 #include "base/strings/stringprintf.h"
8 #include "net/quic/core/congestion_control/simulation/quic_endpoint.h"
9 #include "net/quic/core/congestion_control/simulation/simulator.h"
10 #include "net/quic/core/crypto/crypto_handshake_message.h"
11 #include "net/quic/core/crypto/crypto_protocol.h"
12
13 using base::StringPrintf;
14
15 namespace net {
16 namespace simulation {
17
18 const QuicStreamId kDataStream = 3;
19 const QuicByteCount kWriteChunkSize = 128 * 1024;
20
21 // Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
22 static std::vector<uint32_t> HashNameIntoFive32BitIntegers(std::string name) {
23 const std::string hash = base::SHA1HashString(name);
24
25 std::vector<uint32_t> output;
26 uint32_t current_number = 0;
27 for (size_t i = 0; i < hash.size(); i++) {
28 current_number = (current_number << 8) + hash[i];
29 if (i % 4 == 3) {
30 output.push_back(i);
31 current_number = 0;
32 }
33 }
34
35 return output;
36 }
37
38 IPEndPoint GetAddressFromName(std::string name) {
39 const std::vector<uint32_t> hash = HashNameIntoFive32BitIntegers(name);
40
41 // Generate a random port between 1025 and 65535.
42 const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1);
43
44 // Generate a random 10.x.x.x address, where x is between 1 and 254.
45 std::vector<uint8_t> ip_address;
46 ip_address.push_back(10);
47 for (size_t i = 1; i <= 4; i++) {
48 ip_address.push_back(1 + hash[i] % 254);
49 }
50
51 return IPEndPoint(IPAddress(ip_address), port);
52 }
53
54 QuicEndpoint::QuicEndpoint(Simulator* simulator,
55 std::string name,
56 std::string peer_name,
57 Perspective perspective,
58 QuicConnectionId connection_id)
59 : Endpoint(simulator, name),
60 peer_name_(peer_name),
61 writer_(this),
62 nic_tx_queue_(simulator,
63 StringPrintf("%s (TX Queue)", name.c_str()),
64 kMaxPacketSize * kTxQueueSize),
65 connection_(connection_id,
66 GetAddressFromName(peer_name),
67 simulator,
68 simulator->GetAlarmFactory(),
69 &writer_,
70 false,
71 perspective,
72 CurrentSupportedVersions()),
73 bytes_to_transfer_(0),
74 bytes_transferred_(0),
75 wrong_data_received_(false),
76 transmission_buffer_(new char[kWriteChunkSize]) {
77 connection_.SetSelfAddress(GetAddressFromName(name));
78 connection_.set_visitor(this);
79 connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
80 connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE, new NullDecrypter());
81 connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
82
83 // Configure the connection as if it received a handshake. This is important
84 // primarily because
85 // - this enables pacing, and
86 // - this sets the non-handshake timeouts.
87 std::string error;
88 CryptoHandshakeMessage peer_hello;
89 peer_hello.SetValue(kICSL,
90 static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1));
91 QuicConfig config;
92 QuicErrorCode error_code = config.ProcessPeerHello(
93 peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
94 &error);
95 DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error;
96 connection_.SetFromConfig(config);
97 }
98
99 QuicEndpoint::~QuicEndpoint() {}
100
101 void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) {
102 if (bytes_to_transfer_ > 0) {
103 Schedule(clock_->Now());
104 }
105
106 bytes_to_transfer_ += bytes;
107 WriteStreamData();
108 }
109
110 void QuicEndpoint::AcceptPacket(std::unique_ptr<Packet> packet) {
111 if (packet->destination != name_) {
112 return;
113 }
114
115 QuicReceivedPacket received_packet(packet->contents.data(),
116 packet->contents.size(), clock_->Now());
117 connection_.ProcessUdpPacket(connection_.self_address(),
118 connection_.peer_address(), received_packet);
119 }
120
121 UnconstrainedPortInterface* QuicEndpoint::GetRxPort() {
122 return this;
123 }
124
125 void QuicEndpoint::SetTxPort(ConstrainedPortInterface* port) {
126 // Any egress done by the endpoint is actually handled by a queue on an NIC.
127 nic_tx_queue_.set_tx_port(port);
128 }
129
130 // Return the data that |kDataStream| is supposed to have at offset |offset|.
131 inline static uint8_t DataAtOffset(QuicStreamOffset offset) {
132 return offset % 256;
133 }
134
135 void QuicEndpoint::OnPacketDequeued() {
136 if (writer_.IsWriteBlocked() &&
137 (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
138 kMaxPacketSize) {
139 writer_.SetWritable();
140 connection_.OnCanWrite();
141 }
142 }
143
144 void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) {
145 // Verify that the data received always matches the output of DataAtOffset().
146 DCHECK(frame.stream_id == kDataStream);
147 for (size_t i = 0; i < frame.data_length; i++) {
148 const QuicStreamOffset absolute_offset = frame.offset + i;
149 if (frame.data_buffer[i] != DataAtOffset(absolute_offset)) {
150 wrong_data_received_ = true;
151 }
152 }
153 }
154 void QuicEndpoint::OnCanWrite() {
155 WriteStreamData();
156 }
157 bool QuicEndpoint::WillingAndAbleToWrite() const {
158 return bytes_to_transfer_ != 0;
159 }
160 bool QuicEndpoint::HasPendingHandshake() const {
161 return false;
162 }
163 bool QuicEndpoint::HasOpenDynamicStreams() const {
164 return true;
165 }
166
167 QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
168 : QuicDefaultPacketWriter(0), endpoint_(endpoint) {}
169
170 QuicEndpoint::Writer::~Writer() {}
171
172 WriteResult QuicEndpoint::Writer::WritePacket(const char* buffer,
173 size_t buf_len,
174 const IPAddress& self_address,
175 const IPEndPoint& peer_address,
176 PerPacketOptions* options) {
177 DCHECK(!IsWriteBlocked());
178 DCHECK(options == nullptr);
179 DCHECK(buf_len <= kMaxPacketSize);
180
181 DCHECK(self_address == GetAddressFromName(endpoint_->name()).address());
182 DCHECK(peer_address == GetAddressFromName(endpoint_->peer_name_));
183
184 // Instead of losing a packet, become write-blocked when the egress queue is
185 // full.
186 if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
187 set_write_blocked(true);
188 return WriteResult(WRITE_STATUS_BLOCKED, 0);
189 }
190
191 auto packet = base::MakeUnique<Packet>();
192 packet->source = endpoint_->name();
193 packet->destination = endpoint_->peer_name_;
194 packet->tx_timestamp = endpoint_->clock_->Now();
195
196 packet->contents = std::string(buffer, buf_len);
197 packet->size = buf_len;
198
199 endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet));
200
201 return WriteResult(WRITE_STATUS_OK, buf_len);
202 }
203
204 void QuicEndpoint::WriteStreamData() {
205 // Instantiate a bundler which would normally be here due to QuicSession.
206 QuicConnection::ScopedPacketBundler packet_bundler(&connection_,
207 QuicConnection::SEND_ACK);
208
209 while (bytes_to_transfer_ > 0) {
210 // Transfer data in chunks of size at most |kWriteChunkSize|.
211 const size_t transmission_size =
212 std::min(kWriteChunkSize, bytes_to_transfer_);
213 for (size_t i = 0; i < transmission_size; i++) {
214 const QuicStreamOffset offset = bytes_transferred_ + i;
215 transmission_buffer_[i] = DataAtOffset(offset);
216 }
217
218 iovec iov;
219 iov.iov_base = transmission_buffer_.get();
220 iov.iov_len = transmission_size;
221
222 QuicIOVector io_vector(&iov, 1, transmission_size);
223 QuicConsumedData consumed_data = connection_.SendStreamData(
224 kDataStream, io_vector, bytes_transferred_, false, nullptr);
225
226 DCHECK(consumed_data.bytes_consumed <= transmission_size);
227 bytes_transferred_ += consumed_data.bytes_consumed;
228 bytes_to_transfer_ -= consumed_data.bytes_consumed;
229 if (consumed_data.bytes_consumed != transmission_size) {
230 return;
231 }
232 }
233 }
234
235 QuicEndpointMultiplexer::QuicEndpointMultiplexer(
236 std::string name,
237 std::initializer_list<QuicEndpoint*> endpoints)
238 : Endpoint((*endpoints.begin())->simulator(), name) {
239 for (QuicEndpoint* endpoint : endpoints) {
240 mapping_.insert(std::make_pair(endpoint->name(), endpoint));
241 }
242 }
243
244 QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {}
245
246 void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr<Packet> packet) {
247 auto key_value_pair_it = mapping_.find(packet->destination);
248 if (key_value_pair_it == mapping_.end()) {
249 return;
250 }
251
252 key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet));
253 }
254 UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() {
255 return this;
256 }
257 void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) {
258 for (auto& key_value_pair : mapping_) {
259 key_value_pair.second->SetTxPort(port);
260 }
261 }
262
263 } // namespace simulation
264 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698