diff options
-rw-r--r-- | net/quic/crypto/crypto_protocol.h | 1 | ||||
-rw-r--r-- | net/quic/quic_config.cc | 14 | ||||
-rw-r--r-- | net/quic/quic_config.h | 5 | ||||
-rw-r--r-- | net/quic/quic_config_test.cc | 28 | ||||
-rw-r--r-- | net/quic/quic_connection.cc | 66 | ||||
-rw-r--r-- | net/quic/quic_connection.h | 5 | ||||
-rw-r--r-- | net/quic/quic_connection_test.cc | 40 | ||||
-rw-r--r-- | net/quic/quic_flags.cc | 4 | ||||
-rw-r--r-- | net/quic/quic_flags.h | 1 | ||||
-rw-r--r-- | net/quic/quic_sent_packet_manager.cc | 22 | ||||
-rw-r--r-- | net/quic/quic_sent_packet_manager.h | 5 | ||||
-rw-r--r-- | net/quic/reliable_quic_stream.cc | 9 | ||||
-rw-r--r-- | net/quic/reliable_quic_stream.h | 3 | ||||
-rw-r--r-- | net/quic/reliable_quic_stream_test.cc | 16 | ||||
-rw-r--r-- | net/tools/quic/test_tools/quic_test_client.cc | 21 | ||||
-rw-r--r-- | net/tools/quic/test_tools/quic_test_client.h | 5 |
16 files changed, 199 insertions, 46 deletions
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 3b1a391..beada26 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -78,6 +78,7 @@ const QuicTag kTCID = TAG('T', 'C', 'I', 'D'); // Connection ID truncation. // FEC options const QuicTag kFHDR = TAG('F', 'H', 'D', 'R'); // FEC protect headers +const QuicTag kFSTR = TAG('F', 'S', 'T', 'R'); // FEC protect all streams // Set FecSendPolicy for sending FEC packet only when FEC alarm goes off. const QuicTag kFSPA = TAG('F', 'S', 'P', 'A'); diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 30db003..9277985 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc @@ -388,6 +388,20 @@ QuicTagVector QuicConfig::SendConnectionOptions() const { return connection_options_.GetSendValues(); } +bool QuicConfig::HasClientSentConnectionOption(QuicTag tag, + Perspective perspective) const { + if (perspective == Perspective::IS_SERVER) { + if (HasReceivedConnectionOptions() && + ContainsQuicTag(ReceivedConnectionOptions(), tag)) { + return true; + } + } else if (HasSendConnectionOptions() && + ContainsQuicTag(SendConnectionOptions(), tag)) { + return true; + } + return false; +} + void QuicConfig::SetIdleConnectionStateLifetime( QuicTime::Delta max_idle_connection_state_lifetime, QuicTime::Delta default_idle_conection_state_lifetime) { diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 34ea593..20d71c60 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h @@ -229,6 +229,11 @@ class NET_EXPORT_PRIVATE QuicConfig { QuicTagVector SendConnectionOptions() const; + // Returns true if the client is sending or the server has received a + // connection option. + bool HasClientSentConnectionOption(QuicTag tag, + Perspective perspective) const; + void SetIdleConnectionStateLifetime( QuicTime::Delta max_idle_connection_state_lifetime, QuicTime::Delta default_idle_conection_state_lifetime); diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index 4cd3820..dcf19a5 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc @@ -217,6 +217,34 @@ TEST_F(QuicConfigTest, InvalidFlowControlWindow) { config.GetInitialStreamFlowControlWindowToSend()); } +TEST_F(QuicConfigTest, HasClientSentConnectionOption) { + QuicConfig client_config; + QuicTagVector copt; + copt.push_back(kTBBR); + copt.push_back(kFHDR); + client_config.SetConnectionOptionsToSend(copt); + EXPECT_TRUE(client_config.HasClientSentConnectionOption( + kTBBR, Perspective::IS_CLIENT)); + EXPECT_TRUE(client_config.HasClientSentConnectionOption( + kFHDR, Perspective::IS_CLIENT)); + + CryptoHandshakeMessage msg; + client_config.ToHandshakeMessage(&msg); + + string error_details; + const QuicErrorCode error = + config_.ProcessPeerHello(msg, CLIENT, &error_details); + EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_TRUE(config_.negotiated()); + + EXPECT_TRUE(config_.HasReceivedConnectionOptions()); + EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); + EXPECT_TRUE( + config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER)); + EXPECT_TRUE( + config_.HasClientSentConnectionOption(kFHDR, Perspective::IS_SERVER)); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index b1da304..3ba831f 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -17,6 +17,7 @@ #include "base/debug/stack_trace.h" #include "base/format_macros.h" #include "base/logging.h" +#include "base/memory/ref_counted.h" #include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -178,6 +179,33 @@ class FecAlarm : public QuicAlarm::Delegate { DISALLOW_COPY_AND_ASSIGN(FecAlarm); }; +// Listens for acks of MTU discovery packets and raises the maximum packet size +// of the connection if the probe succeeds. +class MtuDiscoveryAckListener : public QuicAckNotifier::DelegateInterface { + public: + MtuDiscoveryAckListener(QuicConnection* connection, QuicByteCount probe_size) + : connection_(connection), probe_size_(probe_size) {} + + void OnAckNotification(int /*num_retransmittable_packets*/, + int /*num_retransmittable_bytes*/, + QuicTime::Delta /*delta_largest_observed*/) override { + // Since the probe was successful, increase the maximum packet size to that. + if (probe_size_ > connection_->max_packet_length()) { + connection_->set_max_packet_length(probe_size_); + } + } + + protected: + // MtuDiscoveryAckListener is ref counted. + ~MtuDiscoveryAckListener() override {} + + private: + QuicConnection* connection_; + QuicByteCount probe_size_; + + DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAckListener); +}; + } // namespace QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet, @@ -313,12 +341,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { max_undecryptable_packets_ = config.max_undecryptable_packets(); if (FLAGS_quic_send_fec_packet_only_on_fec_alarm && - ((perspective_ == Perspective::IS_SERVER && - config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kFSPA)) || - (perspective_ == Perspective::IS_CLIENT && - config.HasSendConnectionOptions() && - ContainsQuicTag(config.SendConnectionOptions(), kFSPA)))) { + config.HasClientSentConnectionOption(kFSPA, perspective_)) { packet_generator_.set_fec_send_policy(FecSendPolicy::FEC_ALARM_TRIGGER); } } @@ -914,7 +937,7 @@ void QuicConnection::OnPacketComplete() { if (!last_stream_frames_.empty()) { visitor_->OnStreamFrames(last_stream_frames_); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } @@ -926,46 +949,44 @@ void QuicConnection::OnPacketComplete() { // feedback. if (!last_window_update_frames_.empty()) { visitor_->OnWindowUpdateFrames(last_window_update_frames_); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } if (!last_blocked_frames_.empty()) { visitor_->OnBlockedFrames(last_blocked_frames_); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } for (size_t i = 0; i < last_goaway_frames_.size(); ++i) { visitor_->OnGoAway(last_goaway_frames_[i]); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } for (size_t i = 0; i < last_rst_frames_.size(); ++i) { visitor_->OnRstStream(last_rst_frames_[i]); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } for (size_t i = 0; i < last_ack_frames_.size(); ++i) { ProcessAckFrame(last_ack_frames_[i]); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) { ProcessStopWaitingFrame(last_stop_waiting_frames_[i]); - if (!connected_ && FLAGS_quic_stop_early_2) { + if (!connected_) { return; } } if (!last_close_frames_.empty()) { CloseConnection(last_close_frames_[0].error_code, true); DCHECK(!connected_); - if (FLAGS_quic_stop_early_2) { - return; - } + return; } // If there are new missing packets to report, send an ack immediately. @@ -2180,4 +2201,17 @@ bool QuicConnection::IsConnectionClose(const QueuedPacket& packet) { return false; } +void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) { + // Create a listener for the new probe. The ownership of the listener is + // transferred to the AckNotifierManager. The notifier will get destroyed + // before the connection (because it's stored in one of the connection's + // subfields), hence |this| pointer is guaranteed to stay valid at all times. + scoped_refptr<MtuDiscoveryAckListener> last_mtu_discovery_ack_listener( + new MtuDiscoveryAckListener(this, target_mtu)); + + // Send the probe. + packet_generator_.GenerateMtuDiscoveryPacket( + target_mtu, last_mtu_discovery_ack_listener.get()); +} + } // namespace net diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 234782c..f13c589 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -544,6 +544,11 @@ class NET_EXPORT_PRIVATE QuicConnection bool is_secure() const { return is_secure_; } + // Sends an MTU discovery packet of size |target_mtu|. If the packet is + // acknowledged by the peer, the maximum packet size will be increased to + // |target_mtu|. + void SendMtuDiscoveryPacket(QuicByteCount target_mtu); + protected: // Packets which have not been written to the wire. // Owns the QuicPacket* packet. diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index e53e6f0..6747194 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -3220,6 +3220,46 @@ TEST_P(QuicConnectionTest, PingAfterSend) { EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); } +// Tests whether sending an MTU discovery packet to peer successfully causes the +// maximum packet size to increase. +TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) { + EXPECT_TRUE(connection_.connected()); + + // Send an MTU probe. + const size_t new_mtu = kDefaultMaxPacketSize + 100; + QuicByteCount mtu_probe_size; + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<3>(&mtu_probe_size), Return(true))); + connection_.SendMtuDiscoveryPacket(new_mtu); + EXPECT_EQ(new_mtu, mtu_probe_size); + EXPECT_EQ(1u, creator_->sequence_number()); + + // Send more than MTU worth of data. No acknowledgement was received so far, + // so the MTU should be at its old value. + const string data(kDefaultMaxPacketSize + 1, '.'); + QuicByteCount size_before_mtu_change; + // OnPacketSent will be called twice, but only the size of the first packet + // will be stored. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(2) + .WillOnce(DoAll(SaveArg<3>(&size_before_mtu_change), Return(true))); + connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr); + EXPECT_EQ(3u, creator_->sequence_number()); + EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change); + + // Acknowledge all packets so far. + QuicAckFrame probe_ack = InitAckFrame(3); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); + ProcessAckPacket(&probe_ack); + EXPECT_EQ(new_mtu, connection_.max_packet_length()); + + // Send the same data again. Check that it fits into a single packet now. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr); + EXPECT_EQ(4u, creator_->sequence_number()); +} + TEST_P(QuicConnectionTest, TimeoutAfterSend) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 2b57e2a..923a0f0 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc @@ -45,10 +45,6 @@ bool FLAGS_enable_quic_stateless_reject_support = false; // If true, flow controller may grow the receive window size if necessary. bool FLAGS_quic_auto_tune_receive_window = true; -// If true, stop processing quic data as soon as the connection is -// closed rather than processing a full packet. -bool FLAGS_quic_stop_early_2 = true; - // Don't ack acks in QUIC, even when there is a recent missing packet. bool FLAGS_quic_dont_ack_acks = true; diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index fbb185d..aff2c00 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h @@ -19,7 +19,6 @@ NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds; NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support; NET_EXPORT_PRIVATE extern bool FLAGS_quic_auto_tune_receive_window; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early_2; NET_EXPORT_PRIVATE extern bool FLAGS_quic_dont_ack_acks; NET_EXPORT_PRIVATE extern bool FLAGS_quic_send_fec_packet_only_on_fec_alarm; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_is_useless_packet; diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 02bc2af..039a43d 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -146,16 +146,16 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { } EnablePacing(); - if (HasClientSentConnectionOption(config, k1CON)) { + if (config.HasClientSentConnectionOption(k1CON, perspective_)) { send_algorithm_->SetNumEmulatedConnections(1); } - if (HasClientSentConnectionOption(config, kNCON)) { + if (config.HasClientSentConnectionOption(kNCON, perspective_)) { n_connection_simulation_ = true; } - if (HasClientSentConnectionOption(config, kNTLP)) { + if (config.HasClientSentConnectionOption(kNTLP, perspective_)) { max_tail_loss_probes_ = 0; } - if (HasClientSentConnectionOption(config, kNRTO)) { + if (config.HasClientSentConnectionOption(kNRTO, perspective_)) { use_new_rto_ = true; } if (config.HasReceivedConnectionOptions() && @@ -198,20 +198,6 @@ void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) { } } -bool QuicSentPacketManager::HasClientSentConnectionOption( - const QuicConfig& config, QuicTag tag) const { - if (perspective_ == Perspective::IS_SERVER) { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), tag)) { - return true; - } - } else if (config.HasSendConnectionOptions() && - ContainsQuicTag(config.SendConnectionOptions(), tag)) { - return true; - } - return false; -} - void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, QuicTime ack_receive_time) { QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight(); diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index bb65e5e..e0310c0 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -337,11 +337,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { const SequenceNumberList& all_transmissions, QuicPacketSequenceNumber acked_sequence_number); - // Returns true if the client is sending or the server has received a - // connection option. - bool HasClientSentConnectionOption(const QuicConfig& config, - QuicTag tag) const; - // Newly serialized retransmittable and fec packets are added to this map, // which contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 7b1f0e8..924211f 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "net/quic/iovector.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_flow_controller.h" #include "net/quic/quic_session.h" #include "net/quic/quic_write_blocked_list.h" @@ -136,11 +137,19 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session) session_->flow_controller()->auto_tune_receive_window()), connection_flow_controller_(session_->flow_controller()), stream_contributes_to_connection_flow_control_(true) { + SetFromConfig(); } ReliableQuicStream::~ReliableQuicStream() { } +void ReliableQuicStream::SetFromConfig() { + if (FLAGS_quic_send_fec_packet_only_on_fec_alarm && + session_->config()->HasClientSentConnectionOption(kFSTR, perspective_)) { + fec_policy_ = FEC_PROTECT_ALWAYS; + } +} + void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { if (read_side_closed_) { DVLOG(1) << ENDPOINT << "Ignoring frame " << frame.stream_id; diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index a88a835..7496f03 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -48,6 +48,9 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { virtual ~ReliableQuicStream(); + // Sets |fec_policy_| parameter from |session_|'s config. + void SetFromConfig(); + // Called by the session when a (potentially duplicate) stream frame has been // received for this stream. virtual void OnStreamFrame(const QuicStreamFrame& frame); diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 7899ee6..dbdb7b5 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -6,6 +6,7 @@ #include "net/quic/quic_ack_notifier.h" #include "net/quic/quic_connection.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" @@ -696,6 +697,21 @@ TEST_F(ReliableQuicStreamTest, SetDrainingOutgoingIncoming) { EXPECT_EQ(0u, session_->GetNumOpenStreams()); } +TEST_F(ReliableQuicStreamTest, FecSendPolicyReceivedConnectionOption) { + ValueRestore<bool> old_flag(&FLAGS_quic_send_fec_packet_only_on_fec_alarm, + true); + Initialize(kShouldProcessData); + + // Test ReceivedConnectionOptions. + QuicConfig* config = session_->config(); + QuicTagVector copt; + copt.push_back(kFSTR); + QuicConfigPeer::SetReceivedConnectionOptions(config, copt); + EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream_->fec_policy()); + stream_->SetFromConfig(); + EXPECT_EQ(FEC_PROTECT_ALWAYS, stream_->fec_policy()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 75e8728..a1888d9 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -235,6 +235,15 @@ ssize_t QuicTestClient::SendRequest(const string& uri) { return SendMessage(message); } +void QuicTestClient::SendRequestsAndWaitForLastResponse( + const vector<string>& url_list) { + for (const string& url : url_list) { + SendRequest(url); + } + WaitForResponse(); + return; +} + ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) { stream_ = nullptr; // Always force creation of a stream for SendMessage. @@ -316,9 +325,12 @@ string QuicTestClient::SendCustomSynchronousRequest( string QuicTestClient::SendSynchronousRequest(const string& uri) { if (SendRequest(uri) == 0) { DLOG(ERROR) << "Failed the request for uri:" << uri; - return ""; + // Set the response_ explicitly. Otherwise response_ will contain the + // response from the previously successful request. + response_ = ""; + } else { + WaitForResponse(); } - WaitForResponse(); return response_; } @@ -486,6 +498,11 @@ size_t QuicTestClient::bytes_written() const { } void QuicTestClient::OnClose(QuicDataStream* stream) { + if (stream != nullptr) { + // Always close the stream, regardless of whether it was the last stream + // written. + client()->OnClose(stream); + } if (stream_ != stream) { return; } diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 69cdb43..3c164ed 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -99,6 +99,11 @@ class QuicTestClient : public SimpleClient, // Clears any outstanding state and sends a simple GET of 'uri' to the // server. Returns 0 if the request failed and no bytes were written. ssize_t SendRequest(const std::string& uri) override; + // Sends requests for all the urls and waits for the response for the last + // url. To process the individual responses as they are returned, the caller + // should use the set the response_listener on the client(). + void SendRequestsAndWaitForLastResponse( + const std::vector<std::string>& url_list); ssize_t SendMessage(const HTTPMessage& message) override; std::string SendCustomSynchronousRequest(const HTTPMessage& message) override; std::string SendSynchronousRequest(const std::string& uri) override; |