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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: net/quic/core/congestion_control/simulation/quic_endpoint.cc
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint.cc b/net/quic/core/congestion_control/simulation/quic_endpoint.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9e3dde1e4c107eb54db3e40af0f12e1f4da53a18
--- /dev/null
+++ b/net/quic/core/congestion_control/simulation/quic_endpoint.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ptr_util.h"
+#include "base/sha1.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/congestion_control/simulation/quic_endpoint.h"
+#include "net/quic/core/congestion_control/simulation/simulator.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+using base::StringPrintf;
+
+namespace net {
+namespace simulation {
+
+const QuicStreamId kDataStream = 3;
+const QuicByteCount kWriteChunkSize = 128 * 1024;
+
+// Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
+static std::vector<uint32_t> HashNameIntoFive32BitIntegers(std::string name) {
+ const std::string hash = base::SHA1HashString(name);
+
+ std::vector<uint32_t> output;
+ uint32_t current_number = 0;
+ for (size_t i = 0; i < hash.size(); i++) {
+ current_number = (current_number << 8) + hash[i];
+ if (i % 4 == 3) {
+ output.push_back(i);
+ current_number = 0;
+ }
+ }
+
+ return output;
+}
+
+IPEndPoint GetAddressFromName(std::string name) {
+ const std::vector<uint32_t> hash = HashNameIntoFive32BitIntegers(name);
+
+ // Generate a random port between 1025 and 65535.
+ const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1);
+
+ // Generate a random 10.x.x.x address, where x is between 1 and 254.
+ std::vector<uint8_t> ip_address;
+ ip_address.push_back(10);
+ for (size_t i = 1; i <= 4; i++) {
+ ip_address.push_back(1 + hash[i] % 254);
+ }
+
+ return IPEndPoint(IPAddress(ip_address), port);
+}
+
+QuicEndpoint::QuicEndpoint(Simulator* simulator,
+ std::string name,
+ std::string peer_name,
+ Perspective perspective,
+ QuicConnectionId connection_id)
+ : Endpoint(simulator, name),
+ peer_name_(peer_name),
+ writer_(this),
+ nic_tx_queue_(simulator,
+ StringPrintf("%s (TX Queue)", name.c_str()),
+ kMaxPacketSize * kTxQueueSize),
+ connection_(connection_id,
+ GetAddressFromName(peer_name),
+ simulator,
+ simulator->GetAlarmFactory(),
+ &writer_,
+ false,
+ perspective,
+ CurrentSupportedVersions()),
+ bytes_to_transfer_(0),
+ bytes_transferred_(0),
+ wrong_data_received_(false),
+ transmission_buffer_(new char[kWriteChunkSize]) {
+ connection_.SetSelfAddress(GetAddressFromName(name));
+ connection_.set_visitor(this);
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
+ connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE, new NullDecrypter());
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ // Configure the connection as if it received a handshake. This is important
+ // primarily because
+ // - this enables pacing, and
+ // - this sets the non-handshake timeouts.
+ std::string error;
+ CryptoHandshakeMessage peer_hello;
+ peer_hello.SetValue(kICSL,
+ static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1));
+ QuicConfig config;
+ QuicErrorCode error_code = config.ProcessPeerHello(
+ peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
+ &error);
+ DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error;
+ connection_.SetFromConfig(config);
+}
+
+QuicEndpoint::~QuicEndpoint() {}
+
+void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) {
+ if (bytes_to_transfer_ > 0) {
+ Schedule(clock_->Now());
+ }
+
+ bytes_to_transfer_ += bytes;
+ WriteStreamData();
+}
+
+void QuicEndpoint::AcceptPacket(std::unique_ptr<Packet> packet) {
+ if (packet->destination != name_) {
+ return;
+ }
+
+ QuicReceivedPacket received_packet(packet->contents.data(),
+ packet->contents.size(), clock_->Now());
+ connection_.ProcessUdpPacket(connection_.self_address(),
+ connection_.peer_address(), received_packet);
+}
+
+UnconstrainedPortInterface* QuicEndpoint::GetRxPort() {
+ return this;
+}
+
+void QuicEndpoint::SetTxPort(ConstrainedPortInterface* port) {
+ // Any egress done by the endpoint is actually handled by a queue on an NIC.
+ nic_tx_queue_.set_tx_port(port);
+}
+
+// Return the data that |kDataStream| is supposed to have at offset |offset|.
+inline static uint8_t DataAtOffset(QuicStreamOffset offset) {
+ return offset % 256;
+}
+
+void QuicEndpoint::OnPacketDequeued() {
+ if (writer_.IsWriteBlocked() &&
+ (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
+ kMaxPacketSize) {
+ writer_.SetWritable();
+ connection_.OnCanWrite();
+ }
+}
+
+void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) {
+ // Verify that the data received always matches the output of DataAtOffset().
+ DCHECK(frame.stream_id == kDataStream);
+ for (size_t i = 0; i < frame.data_length; i++) {
+ const QuicStreamOffset absolute_offset = frame.offset + i;
+ if (frame.data_buffer[i] != DataAtOffset(absolute_offset)) {
+ wrong_data_received_ = true;
+ }
+ }
+}
+void QuicEndpoint::OnCanWrite() {
+ WriteStreamData();
+}
+bool QuicEndpoint::WillingAndAbleToWrite() const {
+ return bytes_to_transfer_ != 0;
+}
+bool QuicEndpoint::HasPendingHandshake() const {
+ return false;
+}
+bool QuicEndpoint::HasOpenDynamicStreams() const {
+ return true;
+}
+
+QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
+ : QuicDefaultPacketWriter(0), endpoint_(endpoint) {}
+
+QuicEndpoint::Writer::~Writer() {}
+
+WriteResult QuicEndpoint::Writer::WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) {
+ DCHECK(!IsWriteBlocked());
+ DCHECK(options == nullptr);
+ DCHECK(buf_len <= kMaxPacketSize);
+
+ DCHECK(self_address == GetAddressFromName(endpoint_->name()).address());
+ DCHECK(peer_address == GetAddressFromName(endpoint_->peer_name_));
+
+ // Instead of losing a packet, become write-blocked when the egress queue is
+ // full.
+ if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
+ set_write_blocked(true);
+ return WriteResult(WRITE_STATUS_BLOCKED, 0);
+ }
+
+ auto packet = base::MakeUnique<Packet>();
+ packet->source = endpoint_->name();
+ packet->destination = endpoint_->peer_name_;
+ packet->tx_timestamp = endpoint_->clock_->Now();
+
+ packet->contents = std::string(buffer, buf_len);
+ packet->size = buf_len;
+
+ endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet));
+
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+void QuicEndpoint::WriteStreamData() {
+ // Instantiate a bundler which would normally be here due to QuicSession.
+ QuicConnection::ScopedPacketBundler packet_bundler(&connection_,
+ QuicConnection::SEND_ACK);
+
+ while (bytes_to_transfer_ > 0) {
+ // Transfer data in chunks of size at most |kWriteChunkSize|.
+ const size_t transmission_size =
+ std::min(kWriteChunkSize, bytes_to_transfer_);
+ for (size_t i = 0; i < transmission_size; i++) {
+ const QuicStreamOffset offset = bytes_transferred_ + i;
+ transmission_buffer_[i] = DataAtOffset(offset);
+ }
+
+ iovec iov;
+ iov.iov_base = transmission_buffer_.get();
+ iov.iov_len = transmission_size;
+
+ QuicIOVector io_vector(&iov, 1, transmission_size);
+ QuicConsumedData consumed_data = connection_.SendStreamData(
+ kDataStream, io_vector, bytes_transferred_, false, nullptr);
+
+ DCHECK(consumed_data.bytes_consumed <= transmission_size);
+ bytes_transferred_ += consumed_data.bytes_consumed;
+ bytes_to_transfer_ -= consumed_data.bytes_consumed;
+ if (consumed_data.bytes_consumed != transmission_size) {
+ return;
+ }
+ }
+}
+
+QuicEndpointMultiplexer::QuicEndpointMultiplexer(
+ std::string name,
+ std::initializer_list<QuicEndpoint*> endpoints)
+ : Endpoint((*endpoints.begin())->simulator(), name) {
+ for (QuicEndpoint* endpoint : endpoints) {
+ mapping_.insert(std::make_pair(endpoint->name(), endpoint));
+ }
+}
+
+QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {}
+
+void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr<Packet> packet) {
+ auto key_value_pair_it = mapping_.find(packet->destination);
+ if (key_value_pair_it == mapping_.end()) {
+ return;
+ }
+
+ key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet));
+}
+UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() {
+ return this;
+}
+void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) {
+ for (auto& key_value_pair : mapping_) {
+ key_value_pair.second->SetTxPort(port);
+ }
+}
+
+} // namespace simulation
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698