summaryrefslogtreecommitdiffstats
path: root/chromium/net/tools/quic
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/net/tools/quic
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/net/tools/quic')
-rw-r--r--chromium/net/tools/quic/end_to_end_test.cc696
-rw-r--r--chromium/net/tools/quic/quic_client.cc121
-rw-r--r--chromium/net/tools/quic/quic_client.h92
-rw-r--r--chromium/net/tools/quic/quic_client_bin.cc57
-rw-r--r--chromium/net/tools/quic/quic_client_session.cc25
-rw-r--r--chromium/net/tools/quic/quic_client_session.h14
-rw-r--r--chromium/net/tools/quic/quic_client_session_test.cc24
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.cc29
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.h23
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.cc381
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.h149
-rw-r--r--chromium/net/tools/quic/quic_dispatcher_test.cc320
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.h4
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.cc27
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.h16
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache_test.cc2
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.cc48
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.h50
-rw-r--r--chromium/net/tools/quic/quic_server.cc63
-rw-r--r--chromium/net/tools/quic/quic_server.h42
-rw-r--r--chromium/net/tools/quic/quic_server_bin.cc10
-rw-r--r--chromium/net/tools/quic/quic_server_session.cc31
-rw-r--r--chromium/net/tools/quic/quic_server_session.h25
-rw-r--r--chromium/net/tools/quic/quic_server_session_test.cc217
-rw-r--r--chromium/net/tools/quic/quic_server_test.cc32
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.cc68
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.h31
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.cc43
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.h12
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream_test.cc36
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream.cc38
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream.h3
-rw-r--r--chromium/net/tools/quic/quic_spdy_server_stream_test.cc146
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.cc301
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.h198
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager_test.cc439
-rw-r--r--chromium/net/tools/quic/spdy_utils.cc8
-rw-r--r--chromium/net/tools/quic/spdy_utils.h3
-rw-r--r--chromium/net/tools/quic/test_tools/http_message.cc (renamed from chromium/net/tools/quic/test_tools/http_message_test_utils.cc)4
-rw-r--r--chromium/net/tools/quic/test_tools/http_message.h (renamed from chromium/net/tools/quic/test_tools/http_message_test_utils.h)8
-rw-r--r--chromium/net/tools/quic/test_tools/mock_epoll_server.h12
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc11
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h9
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc78
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h38
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.cc14
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.h12
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc21
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h20
-rw-r--r--chromium/net/tools/quic/test_tools/quic_server_peer.cc5
-rw-r--r--chromium/net/tools/quic/test_tools/quic_server_peer.h6
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.cc349
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.h162
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_utils.cc60
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_utils.h100
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.cc45
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.h21
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.cc36
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.h159
59 files changed, 3285 insertions, 1709 deletions
diff --git a/chromium/net/tools/quic/end_to_end_test.cc b/chromium/net/tools/quic/end_to_end_test.cc
index 2b94b0f2fd1..a21dc4082a3 100644
--- a/chromium/net/tools/quic/end_to_end_test.cc
+++ b/chromium/net/tools/quic/end_to_end_test.cc
@@ -4,30 +4,39 @@
#include <stddef.h>
#include <string>
+#include <sys/epoll.h>
#include <vector>
+#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/congestion_control/tcp_cubic_sender.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/null_encrypter.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_sent_packet_manager.h"
+#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/test/gtest_util.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_in_memory_cache.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/quic_socket_utils.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
-#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
#include "net/tools/quic/test_tools/packet_dropping_test_writer.h"
#include "net/tools/quic/test_tools/quic_client_peer.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
@@ -39,10 +48,14 @@
using base::StringPiece;
using base::WaitableEvent;
+using net::EpollServer;
+using net::test::GenerateBody;
using net::test::QuicConnectionPeer;
+using net::test::QuicFlowControllerPeer;
using net::test::QuicSessionPeer;
-using net::test::QuicTestWriter;
using net::test::ReliableQuicStreamPeer;
+using net::test::ValueRestore;
+using net::test::kClientDataStreamId1;
using net::tools::test::PacketDroppingTestWriter;
using net::tools::test::QuicDispatcherPeer;
using net::tools::test::QuicServerPeer;
@@ -58,14 +71,6 @@ namespace {
const char* kFooResponseBody = "Artichoke hearts make me happy.";
const char* kBarResponseBody = "Palm hearts are pretty delicious, also.";
-void GenerateBody(string* body, int length) {
- body->clear();
- body->reserve(length);
- for (int i = 0; i < length; ++i) {
- body->append(1, static_cast<char>(32 + i % (126 - 32)));
- }
-}
-
// Run all tests with the cross products of all versions.
struct TestParams {
TestParams(const QuicVersionVector& client_supported_versions,
@@ -98,7 +103,6 @@ struct TestParams {
vector<TestParams> GetTestParams() {
vector<TestParams> params;
QuicVersionVector all_supported_versions = QuicSupportedVersions();
-
for (int use_pacing = 0; use_pacing < 2; ++use_pacing) {
// Add an entry for server and client supporting all versions.
params.push_back(TestParams(all_supported_versions,
@@ -106,19 +110,6 @@ vector<TestParams> GetTestParams() {
all_supported_versions[0],
use_pacing != 0));
- // Test client supporting 1 version and server supporting all versions.
- // Simulate an old client and exercise version downgrade in the server.
- // No protocol negotiation should occur. Skip the i = 0 case because it
- // is essentially the same as the default case.
- for (size_t i = 1; i < all_supported_versions.size(); ++i) {
- QuicVersionVector client_supported_versions;
- client_supported_versions.push_back(all_supported_versions[i]);
- params.push_back(TestParams(client_supported_versions,
- all_supported_versions,
- client_supported_versions[0],
- use_pacing != 0));
- }
-
// Test client supporting all versions and server supporting 1 version.
// Simulate an old server and exercise version downgrade in the client.
// Protocol negotiation should occur. Skip the i = 0 case because it is
@@ -126,6 +117,12 @@ vector<TestParams> GetTestParams() {
for (size_t i = 1; i < all_supported_versions.size(); ++i) {
QuicVersionVector server_supported_versions;
server_supported_versions.push_back(all_supported_versions[i]);
+ if (all_supported_versions[i] >= QUIC_VERSION_17) {
+ // Until flow control is globally rolled out and we remove
+ // QUIC_VERSION_16, the server MUST support at least one QUIC version
+ // that does not use flow control.
+ server_supported_versions.push_back(QUIC_VERSION_16);
+ }
params.push_back(TestParams(all_supported_versions,
server_supported_versions,
server_supported_versions[0],
@@ -135,6 +132,28 @@ vector<TestParams> GetTestParams() {
return params;
}
+class ServerDelegate : public PacketDroppingTestWriter::Delegate {
+ public:
+ explicit ServerDelegate(QuicDispatcher* dispatcher)
+ : dispatcher_(dispatcher) {}
+ virtual ~ServerDelegate() {}
+ virtual void OnCanWrite() OVERRIDE { dispatcher_->OnCanWrite(); }
+ private:
+ QuicDispatcher* dispatcher_;
+};
+
+class ClientDelegate : public PacketDroppingTestWriter::Delegate {
+ public:
+ explicit ClientDelegate(QuicClient* client) : client_(client) {}
+ virtual ~ClientDelegate() {}
+ virtual void OnCanWrite() OVERRIDE {
+ EpollEvent event(EPOLLOUT, false);
+ client_->OnEvent(client_->fd(), &event);
+ }
+ private:
+ QuicClient* client_;
+};
+
class EndToEndTest : public ::testing::TestWithParam<TestParams> {
protected:
EndToEndTest()
@@ -148,14 +167,32 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
client_supported_versions_ = GetParam().client_supported_versions;
server_supported_versions_ = GetParam().server_supported_versions;
negotiated_version_ = GetParam().negotiated_version;
- FLAGS_limit_rto_increase_for_tests = true;
FLAGS_enable_quic_pacing = GetParam().use_pacing;
- LOG(INFO) << "Using Configuration: " << GetParam();
+
+ if (negotiated_version_ >= QUIC_VERSION_17) {
+ FLAGS_enable_quic_stream_flow_control_2 = true;
+ }
+ if (negotiated_version_ >= QUIC_VERSION_19) {
+ FLAGS_enable_quic_connection_flow_control_2 = true;
+ }
+ VLOG(1) << "Using Configuration: " << GetParam();
client_config_.SetDefaults();
server_config_.SetDefaults();
- server_config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs,
- 0);
+
+ // Use different flow control windows for client/server.
+ client_config_.SetInitialFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ client_config_.SetInitialStreamFlowControlWindowToSend(
+ 2 * kInitialStreamFlowControlWindowForTest);
+ client_config_.SetInitialSessionFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ server_config_.SetInitialFlowControlWindowToSend(
+ 3 * kInitialSessionFlowControlWindowForTest);
+ server_config_.SetInitialStreamFlowControlWindowToSend(
+ 3 * kInitialStreamFlowControlWindowForTest);
+ server_config_.SetInitialSessionFlowControlWindowToSend(
+ 3 * kInitialSessionFlowControlWindowForTest);
QuicInMemoryCachePeer::ResetForTests();
AddToCache("GET", "https://www.google.com/foo",
@@ -170,54 +207,99 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
QuicInMemoryCachePeer::ResetForTests();
}
- virtual QuicTestClient* CreateQuicClient(QuicTestWriter* writer) {
- QuicTestClient* client = new QuicTestClient(server_address_,
- server_hostname_,
- false, // not secure
- client_config_,
- client_supported_versions_);
+ QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) {
+ QuicTestClient* client = new QuicTestClient(
+ server_address_,
+ server_hostname_,
+ false, // not secure
+ client_config_,
+ client_supported_versions_);
client->UseWriter(writer);
client->Connect();
return client;
}
- virtual bool Initialize() {
+ void set_client_initial_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DVLOG(1) << "Setting client initial flow control window: " << window;
+ client_config_.SetInitialFlowControlWindowToSend(window);
+ }
+
+ void set_client_initial_stream_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DLOG(INFO) << "Setting client initial stream flow control window: "
+ << window;
+ client_config_.SetInitialStreamFlowControlWindowToSend(window);
+ }
+
+ void set_client_initial_session_flow_control_receive_window(uint32 window) {
+ CHECK(client_.get() == NULL);
+ DLOG(INFO) << "Setting client initial session flow control window: "
+ << window;
+ client_config_.SetInitialSessionFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DVLOG(1) << "Setting server initial flow control window: " << window;
+ server_config_.SetInitialFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_stream_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DLOG(INFO) << "Setting server initial stream flow control window: "
+ << window;
+ server_config_.SetInitialStreamFlowControlWindowToSend(window);
+ }
+
+ void set_server_initial_session_flow_control_receive_window(uint32 window) {
+ CHECK(server_thread_.get() == NULL);
+ DLOG(INFO) << "Setting server initial session flow control window: "
+ << window;
+ server_config_.SetInitialSessionFlowControlWindowToSend(window);
+ }
+
+ bool Initialize() {
// Start the server first, because CreateQuicClient() attempts
// to connect to the server.
StartServer();
client_.reset(CreateQuicClient(client_writer_));
- QuicEpollConnectionHelper* helper =
+ static EpollEvent event(EPOLLOUT, false);
+ client_writer_->Initialize(
reinterpret_cast<QuicEpollConnectionHelper*>(
QuicConnectionPeer::GetHelper(
- client_->client()->session()->connection()));
- client_writer_->SetConnectionHelper(helper);
+ client_->client()->session()->connection())),
+ new ClientDelegate(client_->client()));
return client_->client()->connected();
}
- virtual void SetUp() {
- // The ownership of these gets transferred to the QuicTestWriter and
- // QuicDispatcher when Initialize() is executed.
+ virtual void SetUp() OVERRIDE {
+ // The ownership of these gets transferred to the QuicPacketWriterWrapper
+ // and QuicDispatcher when Initialize() is executed.
client_writer_ = new PacketDroppingTestWriter();
server_writer_ = new PacketDroppingTestWriter();
}
- virtual void TearDown() {
+ virtual void TearDown() OVERRIDE {
StopServer();
}
void StartServer() {
- server_thread_.reset(new ServerThread(server_address_, server_config_,
- server_supported_versions_,
- strike_register_no_startup_period_));
- server_thread_->Start();
- server_thread_->WaitForServerStartup();
+ server_thread_.reset(
+ new ServerThread(
+ new QuicServer(server_config_, server_supported_versions_),
+ server_address_,
+ strike_register_no_startup_period_));
+ server_thread_->Initialize();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
- server_writer_->SetConnectionHelper(
- QuicDispatcherPeer::GetHelper(dispatcher));
QuicDispatcherPeer::UseWriter(dispatcher, server_writer_);
+ server_writer_->Initialize(
+ QuicDispatcherPeer::GetHelper(dispatcher),
+ new ServerDelegate(dispatcher));
+ server_thread_->Start();
server_started_ = true;
}
@@ -243,8 +325,10 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
void SetPacketLossPercentage(int32 loss) {
// TODO(rtenneti): enable when we can do random packet loss tests in
// chrome's tree.
- // client_writer_->set_fake_packet_loss_percentage(loss);
- // server_writer_->set_fake_packet_loss_percentage(loss);
+ if (loss != 0 && loss != 100)
+ return;
+ client_writer_->set_fake_packet_loss_percentage(loss);
+ server_writer_->set_fake_packet_loss_percentage(loss);
}
void SetPacketSendDelay(QuicTime::Delta delay) {
@@ -261,6 +345,36 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
// server_writer_->set_fake_reorder_percentage(reorder);
}
+ // Verifies that the client and server connections were both free of packets
+ // being discarded, based on connection stats.
+ // Calls server_thread_ Pause() and Resume(), which may only be called once
+ // per test.
+ void VerifyCleanConnection(bool had_packet_loss) {
+ QuicConnectionStats client_stats =
+ client_->client()->session()->connection()->GetStats();
+ if (!had_packet_loss) {
+ EXPECT_EQ(0u, client_stats.packets_lost);
+ }
+ EXPECT_EQ(0u, client_stats.packets_discarded);
+ EXPECT_EQ(0u, client_stats.packets_dropped);
+ EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed);
+
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ ASSERT_EQ(1u, dispatcher->session_map().size());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ QuicConnectionStats server_stats = session->connection()->GetStats();
+ if (!had_packet_loss) {
+ EXPECT_EQ(0u, server_stats.packets_lost);
+ }
+ EXPECT_EQ(0u, server_stats.packets_discarded);
+ // TODO(ianswett): Restore the check for packets_dropped equals 0.
+ // The expect for packets received is equal to packets processed fails
+ // due to version negotiation packets.
+ server_thread_->Resume();
+ }
+
IPEndPoint server_address_;
string server_hostname_;
scoped_ptr<ServerThread> server_thread_;
@@ -398,12 +512,14 @@ TEST_P(EndToEndTest, PostMissingBytes) {
EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
}
-TEST_P(EndToEndTest, LargePostNoPacketLoss) {
+// TODO(rtenneti): DISABLED_LargePostNoPacketLoss seems to be flaky.
+// http://crbug.com/297040.
+TEST_P(EndToEndTest, DISABLED_LargePostNoPacketLoss) {
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
- // 1 Mb body.
+ // 1 MB body.
string body;
GenerateBody(&body, 1024 * 1024);
@@ -412,6 +528,25 @@ TEST_P(EndToEndTest, LargePostNoPacketLoss) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(false);
+}
+
+TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) {
+ ASSERT_TRUE(Initialize());
+ SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(1000));
+
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // 100 KB body.
+ string body;
+ GenerateBody(&body, 100 * 1024);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1,
+ HttpConstants::POST, "/foo");
+ request.AddBody(body, true);
+
+ EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(false);
}
TEST_P(EndToEndTest, LargePostWithPacketLoss) {
@@ -424,7 +559,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
client_->client()->WaitForCryptoHandshakeConfirmed();
SetPacketLossPercentage(30);
- // 10 Kb body.
+ // 10 KB body.
string body;
GenerateBody(&body, 1024 * 10);
@@ -433,19 +568,23 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(true);
}
-TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
+TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) {
+ // Connect with lower fake packet loss than we'd like to test. Until
+ // b/10126687 is fixed, losing handshake packets is pretty brutal.
+ SetPacketLossPercentage(5);
ASSERT_TRUE(Initialize());
+ // Wait for the server SHLO before upping the packet loss.
client_->client()->WaitForCryptoHandshakeConfirmed();
- // Both of these must be called when the writer is not actively used.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
+ SetPacketLossPercentage(10);
+ client_writer_->set_fake_blocked_socket_percentage(10);
- // 1 Mb body.
+ // 10 KB body.
string body;
- GenerateBody(&body, 1024 * 1024);
+ GenerateBody(&body, 1024 * 10);
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
@@ -454,20 +593,17 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
-TEST_P(EndToEndTest, LargePostWithPacketLossAndBlocketSocket) {
- // Connect with lower fake packet loss than we'd like to test. Until
- // b/10126687 is fixed, losing handshake packets is pretty brutal.
- SetPacketLossPercentage(5);
+TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) {
ASSERT_TRUE(Initialize());
- // Wait for the server SHLO before upping the packet loss.
client_->client()->WaitForCryptoHandshakeConfirmed();
- SetPacketLossPercentage(30);
- client_writer_->set_fake_blocked_socket_percentage(10);
+ // Both of these must be called when the writer is not actively used.
+ SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
+ SetReorderPercentage(30);
- // 10 Kb body.
+ // 1 MB body.
string body;
- GenerateBody(&body, 1024 * 10);
+ GenerateBody(&body, 1024 * 1024);
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
@@ -500,6 +636,14 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
// The 0-RTT handshake should succeed.
client_->Connect();
+ if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
+ negotiated_version_ < QUIC_VERSION_17) {
+ // If the version negotiation has resulted in a downgrade, then the client
+ // must wait for the handshake to complete before sending any data.
+ // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+ // DFATAL when they are serialized after the downgrade.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ }
client_->WaitForResponseForMs(-1);
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
@@ -513,16 +657,35 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
StartServer();
client_->Connect();
+ if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
+ negotiated_version_ < QUIC_VERSION_17) {
+ // If the version negotiation has resulted in a downgrade, then the client
+ // must wait for the handshake to complete before sending any data.
+ // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+ // DFATAL when they are serialized after the downgrade.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ }
ASSERT_TRUE(client_->client()->connected());
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
EXPECT_EQ(2, client_->client()->session()->GetNumSentClientHellos());
+ VerifyCleanConnection(false);
}
-// TODO(ianswett): Enable once b/9295090 is fixed.
-TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
- SetPacketLossPercentage(30);
+TEST_P(EndToEndTest, LargePostFEC) {
+ // Connect without packet loss to avoid issues with losing handshake packets,
+ // and then up the packet loss rate (b/10126687).
ASSERT_TRUE(Initialize());
- client_->options()->max_packets_per_fec_group = 6;
+
+ // Wait for the server SHLO before upping the packet loss.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ SetPacketLossPercentage(30);
+
+ // Enable FEC protection.
+ QuicPacketCreator* creator = QuicConnectionPeer::GetPacketCreator(
+ client_->client()->session()->connection());
+ creator->set_max_packets_per_fec_group(3);
+ // Set FecPolicy to always protect data on all streams.
+ client_->SetFecPolicy(FEC_PROTECT_ALWAYS);
string body;
GenerateBody(&body, 10240);
@@ -530,21 +693,23 @@ TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
HTTPMessage request(HttpConstants::HTTP_1_1,
HttpConstants::POST, "/foo");
request.AddBody(body, true);
-
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ VerifyCleanConnection(true);
}
-TEST_P(EndToEndTest, LargePostLargeBuffer) {
+// TODO(shess): This is flaky on ChromiumOS bots.
+// http://crbug.com/374871
+TEST_P(EndToEndTest, DISABLED_LargePostSmallBandwidthLargeBuffer) {
ASSERT_TRUE(Initialize());
SetPacketSendDelay(QuicTime::Delta::FromMicroseconds(1));
- // 1Mbit per second with a 128k buffer from server to client. Wireless
+ // 256KB per second with a 256KB buffer from server to client. Wireless
// clients commonly have larger buffers, but our max CWND is 200.
server_writer_->set_max_bandwidth_and_buffer_size(
- QuicBandwidth::FromBytesPerSecond(256 * 1024), 128 * 1024);
+ QuicBandwidth::FromBytesPerSecond(256 * 1024), 256 * 1024);
client_->client()->WaitForCryptoHandshakeConfirmed();
- // 1 Mb body.
+ // 1 MB body.
string body;
GenerateBody(&body, 1024 * 1024);
@@ -553,6 +718,52 @@ TEST_P(EndToEndTest, LargePostLargeBuffer) {
request.AddBody(body, true);
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+ // This connection will not drop packets, because the buffer size is larger
+ // than the default receive window.
+ VerifyCleanConnection(false);
+}
+
+TEST_P(EndToEndTest, DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked) {
+ // Regression test for b/14677858.
+ // Test that the resume write alarm is not set in QuicConnection::OnCanWrite
+ // if currently connection level flow control blocked. If set, this results in
+ // an infinite loop in the EpollServer, as the alarm fires and is immediately
+ // rescheduled.
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ < QUIC_VERSION_19) {
+ return;
+ }
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Ensure both stream and connection level are flow control blocked by setting
+ // the send window offset to 0.
+ const uint64 kFlowControlWindow =
+ server_config_.GetInitialFlowControlWindowToSend();
+ QuicSpdyClientStream* stream = client_->GetOrCreateStream();
+ QuicSession* session = client_->client()->session();
+ QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0);
+ QuicFlowControllerPeer::SetSendWindowOffset(session->flow_controller(), 0);
+ EXPECT_TRUE(stream->flow_controller()->IsBlocked());
+ EXPECT_TRUE(session->flow_controller()->IsBlocked());
+
+ // Make sure that the stream has data pending so that it will be marked as
+ // write blocked when it receives a stream level WINDOW_UPDATE.
+ stream->SendBody("hello", false);
+
+ // The stream now attempts to write, fails because it is still connection
+ // level flow control blocked, and is added to the write blocked list.
+ QuicWindowUpdateFrame window_update(stream->id(), 2 * kFlowControlWindow);
+ stream->OnWindowUpdateFrame(window_update);
+
+ // Prior to fixing b/14677858 this call would result in an infinite loop in
+ // Chromium. As a proxy for detecting this, we now check whether the
+ // resume_writes_alarm is set after OnCanWrite. It should not be, as the
+ // connection is still flow control blocked.
+ session->connection()->OnCanWrite();
+
+ QuicAlarm* resume_writes_alarm =
+ QuicConnectionPeer::GetResumeWritesAlarm(session->connection());
+ EXPECT_FALSE(resume_writes_alarm->IsSet());
}
TEST_P(EndToEndTest, InvalidStream) {
@@ -570,7 +781,7 @@ TEST_P(EndToEndTest, InvalidStream) {
QuicSessionPeer::SetNextStreamId(client_->client()->session(), 2);
client_->SendCustomSynchronousRequest(request);
-// EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ // EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
EXPECT_EQ(QUIC_PACKET_FOR_NONEXISTENT_STREAM, client_->connection_error());
}
@@ -598,23 +809,7 @@ TEST_P(EndToEndTest, DISABLED_MultipleTermination) {
ReliableQuicStreamPeer::SetWriteSideClosed(
false, client_->GetOrCreateStream());
-#if !defined(WIN32) && defined(GTEST_HAS_DEATH_TEST)
-#if !defined(DCHECK_ALWAYS_ON)
- EXPECT_DEBUG_DEATH({
- client_->SendData("eep", true);
- client_->WaitForResponse();
- EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS, client_->stream_error());
- },
- "Check failed: !fin_buffered_");
-#else
- EXPECT_DEATH({
- client_->SendData("eep", true);
- client_->WaitForResponse();
- EXPECT_EQ(QUIC_MULTIPLE_TERMINATION_OFFSETS, client_->stream_error());
- },
- "Check failed: !fin_buffered_");
-#endif
-#endif
+ EXPECT_DFATAL(client_->SendData("eep", true), "Fin already buffered");
}
TEST_P(EndToEndTest, Timeout) {
@@ -629,6 +824,30 @@ TEST_P(EndToEndTest, Timeout) {
}
}
+TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
+ // Negotiate 1 max open stream.
+ client_config_.set_max_streams_per_connection(1, 1);
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Make the client misbehave after negotiation.
+ QuicSessionPeer::SetMaxOpenStreams(client_->client()->session(), 10);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1,
+ HttpConstants::POST, "/foo");
+ request.AddHeader("content-length", "3");
+ request.set_has_complete_message(false);
+
+ // Open two simultaneous streams.
+ client_->SendMessage(request);
+ client_->SendMessage(request);
+ client_->WaitForResponse();
+
+ EXPECT_FALSE(client_->connected());
+ EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
+}
+
TEST_P(EndToEndTest, LimitMaxOpenStreams) {
// Server limits the number of max streams to 2.
server_config_.set_max_streams_per_connection(2, 2);
@@ -644,13 +863,10 @@ TEST_P(EndToEndTest, LimitMaxOpenStreams) {
// TODO(rtenneti): DISABLED_LimitCongestionWindowAndRTT seems to be flaky.
// http://crbug.com/321870.
TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
- server_config_.set_server_initial_congestion_window(kMaxInitialWindow,
- kDefaultInitialWindow);
- // Client tries to negotiate twice the server's max and negotiation settles
- // on the max.
- client_config_.set_server_initial_congestion_window(2 * kMaxInitialWindow,
- kDefaultInitialWindow);
- client_config_.set_initial_round_trip_time_us(1, 1);
+ // Client tries to request twice the server's max initial window, and the
+ // server limits it to the max.
+ client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
+ client_config_.SetInitialRoundTripTimeUsToSend(1);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -662,17 +878,11 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
- QuicConfig* client_negotiated_config = client_->client()->session()->config();
- QuicConfig* server_negotiated_config = session->config();
const QuicSentPacketManager& client_sent_packet_manager =
client_->client()->session()->connection()->sent_packet_manager();
const QuicSentPacketManager& server_sent_packet_manager =
session->connection()->sent_packet_manager();
- EXPECT_EQ(kMaxInitialWindow,
- client_negotiated_config->server_initial_congestion_window());
- EXPECT_EQ(kMaxInitialWindow,
- server_negotiated_config->server_initial_congestion_window());
// The client shouldn't set it's initial window based on the negotiated value.
EXPECT_EQ(kDefaultInitialWindow * kDefaultTCPMSS,
client_sent_packet_manager.GetCongestionWindow());
@@ -684,13 +894,14 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
EXPECT_EQ(FLAGS_enable_quic_pacing,
client_sent_packet_manager.using_pacing());
- EXPECT_EQ(1u, client_negotiated_config->initial_round_trip_time_us());
- EXPECT_EQ(1u, server_negotiated_config->initial_round_trip_time_us());
+ EXPECT_EQ(100000u,
+ client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_EQ(1u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
// Now use the negotiated limits with packet loss.
SetPacketLossPercentage(30);
- // 10 Kb body.
+ // 10 KB body.
string body;
GenerateBody(&body, 1024 * 10);
@@ -703,11 +914,42 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
-TEST_P(EndToEndTest, InitialRTT) {
- // Client tries to negotiate twice the server's max and negotiation settles
- // on the max.
- client_config_.set_initial_round_trip_time_us(2 * kMaxInitialRoundTripTimeUs,
- 0);
+TEST_P(EndToEndTest, MaxInitialRTT) {
+ // Client tries to suggest twice the server's max initial rtt and the server
+ // uses the max.
+ client_config_.SetInitialRoundTripTimeUsToSend(
+ 2 * kMaxInitialRoundTripTimeUs);
+
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Pause the server so we can access the server's internals without races.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ ASSERT_EQ(1u, dispatcher->session_map().size());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ const QuicSentPacketManager& client_sent_packet_manager =
+ client_->client()->session()->connection()->sent_packet_manager();
+ const QuicSentPacketManager& server_sent_packet_manager =
+ session->connection()->sent_packet_manager();
+
+ // Now that acks have been exchanged, the RTT estimate has decreased on the
+ // server and is not infinite on the client.
+ EXPECT_FALSE(
+ client_sent_packet_manager.GetRttStats()->SmoothedRtt().IsInfinite());
+ EXPECT_EQ(static_cast<int64>(kMaxInitialRoundTripTimeUs),
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_GE(
+ static_cast<int64>(kMaxInitialRoundTripTimeUs),
+ server_sent_packet_manager.GetRttStats()->SmoothedRtt().ToMicroseconds());
+ server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, MinInitialRTT) {
+ // Client tries to suggest 0 and the server uses the default.
+ client_config_.SetInitialRoundTripTimeUsToSend(0);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -719,22 +961,22 @@ TEST_P(EndToEndTest, InitialRTT) {
QuicServerPeer::GetDispatcher(server_thread_->server());
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
- QuicConfig* client_negotiated_config = client_->client()->session()->config();
- QuicConfig* server_negotiated_config = session->config();
const QuicSentPacketManager& client_sent_packet_manager =
client_->client()->session()->connection()->sent_packet_manager();
const QuicSentPacketManager& server_sent_packet_manager =
session->connection()->sent_packet_manager();
- EXPECT_EQ(kMaxInitialRoundTripTimeUs,
- client_negotiated_config->initial_round_trip_time_us());
- EXPECT_EQ(kMaxInitialRoundTripTimeUs,
- server_negotiated_config->initial_round_trip_time_us());
// Now that acks have been exchanged, the RTT estimate has decreased on the
// server and is not infinite on the client.
- EXPECT_FALSE(client_sent_packet_manager.SmoothedRtt().IsInfinite());
- EXPECT_GE(static_cast<int64>(kMaxInitialRoundTripTimeUs),
- server_sent_packet_manager.SmoothedRtt().ToMicroseconds());
+ EXPECT_FALSE(
+ client_sent_packet_manager.GetRttStats()->SmoothedRtt().IsInfinite());
+ // Expect the default rtt of 100ms.
+ EXPECT_EQ(static_cast<int64>(100 * base::Time::kMicrosecondsPerMillisecond),
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ // Ensure the bandwidth is valid.
+ client_sent_packet_manager.BandwidthEstimate();
+ server_sent_packet_manager.BandwidthEstimate();
+ server_thread_->Resume();
}
TEST_P(EndToEndTest, ResetConnection) {
@@ -770,7 +1012,35 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) {
}
}
-class WrongAddressWriter : public QuicTestWriter {
+TEST_P(EndToEndTest, StreamCancelErrorTest) {
+ ASSERT_TRUE(Initialize());
+ string small_body;
+ GenerateBody(&small_body, 256);
+
+ AddToCache("GET", "/small_response", "HTTP/1.1", "200", "OK", small_body);
+
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ QuicSession* session = client_->client()->session();
+ // Lose the request.
+ SetPacketLossPercentage(100);
+ EXPECT_LT(0, client_->SendRequest("/small_response"));
+ client_->client()->WaitForEvents();
+ // Transmit the cancel, and ensure the connection is torn down properly.
+ SetPacketLossPercentage(0);
+ QuicStreamId stream_id = kClientDataStreamId1;
+ session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+
+ // WaitForEvents waits 50ms and returns true if there are outstanding
+ // requests.
+ while (client_->client()->WaitForEvents() == true) {
+ }
+ // It should be completely fine to RST a stream before any data has been
+ // received for that stream.
+ EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
+}
+
+class WrongAddressWriter : public QuicPacketWriterWrapper {
public:
WrongAddressWriter() {
IPAddressNumber ip;
@@ -779,12 +1049,13 @@ class WrongAddressWriter : public QuicTestWriter {
}
virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& real_self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
- return writer()->WritePacket(buffer, buf_len, self_address_.address(),
- peer_address, blocked_writer);
+ const IPEndPoint& peer_address) OVERRIDE {
+ // Use wrong address!
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address_.address(), peer_address);
}
virtual bool IsWriteBlockedDataBuffered() const OVERRIDE {
@@ -794,7 +1065,10 @@ class WrongAddressWriter : public QuicTestWriter {
IPEndPoint self_address_;
};
-TEST_P(EndToEndTest, ConnectionMigration) {
+TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) {
+ // Tests that the client's IP can not change during an established QUIC
+ // connection. If it changes, the connection is closed by the server as we do
+ // not yet support IP migration.
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -802,8 +1076,7 @@ TEST_P(EndToEndTest, ConnectionMigration) {
scoped_ptr<WrongAddressWriter> writer(new WrongAddressWriter());
- writer->set_writer(new QuicDefaultPacketWriter(
- QuicClientPeer::GetFd(client_->client())));
+ writer->set_writer(new QuicDefaultPacketWriter(client_->client()->fd()));
QuicConnectionPeer::SetWriter(client_->client()->session()->connection(),
writer.get());
@@ -813,6 +1086,157 @@ TEST_P(EndToEndTest, ConnectionMigration) {
EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS, client_->connection_error());
}
+TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) {
+ // Tests that the client's port can change during an established QUIC
+ // connection, and that doing so does not result in the connection being
+ // closed by the server.
+ FLAGS_quic_allow_port_migration = true;
+
+ ASSERT_TRUE(Initialize());
+
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+ // Store the client address which was used to send the first request.
+ IPEndPoint old_address = client_->client()->client_address();
+
+ // Stop listening on the old FD.
+ EpollServer* eps = client_->epoll_server();
+ int old_fd = client_->client()->fd();
+ eps->UnregisterFD(old_fd);
+ // Create a new socket before closing the old one, which will result in a new
+ // ephemeral port.
+ QuicClientPeer::CreateUDPSocket(client_->client());
+ close(old_fd);
+
+ // The packet writer needs to be updated to use the new FD.
+ client_->client()->CreateQuicPacketWriter();
+
+ // Change the internal state of the client and connection to use the new port,
+ // this is done because in a real NAT rebinding the client wouldn't see any
+ // port change, and so expects no change to incoming port.
+ // This is kind of ugly, but needed as we are simply swapping out the client
+ // FD rather than any more complex NAT rebinding simulation.
+ int new_port = client_->client()->client_address().port();
+ QuicClientPeer::SetClientPort(client_->client(), new_port);
+ QuicConnectionPeer::SetSelfAddress(
+ client_->client()->session()->connection(),
+ IPEndPoint(
+ client_->client()->session()->connection()->self_address().address(),
+ new_port));
+
+ // Register the new FD for epoll events.
+ int new_fd = client_->client()->fd();
+ eps->RegisterFD(new_fd, client_->client(), EPOLLIN | EPOLLOUT | EPOLLET);
+
+ // Send a second request, using the new FD.
+ EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+ // Verify that the client's ephemeral port is different.
+ IPEndPoint new_address = client_->client()->client_address();
+ EXPECT_EQ(old_address.address(), new_address.address());
+ EXPECT_NE(old_address.port(), new_address.port());
+}
+
+
+TEST_P(EndToEndTest, DifferentFlowControlWindowsQ019) {
+ // TODO(rjshade): Remove this test when removing QUIC_VERSION_19.
+ // Client and server can set different initial flow control receive windows.
+ // These are sent in CHLO/SHLO. Tests that these values are exchanged properly
+ // in the crypto handshake.
+
+ const uint32 kClientIFCW = 123456;
+ set_client_initial_flow_control_receive_window(kClientIFCW);
+
+ const uint32 kServerIFCW = 654321;
+ set_server_initial_flow_control_receive_window(kServerIFCW);
+
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ > QUIC_VERSION_19) {
+ return;
+ }
+
+ // Values are exchanged during crypto handshake, so wait for that to finish.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Client should have the right value for server's receive window.
+ EXPECT_EQ(kServerIFCW, client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialFlowControlWindowBytes());
+
+ // Server should have the right value for client's receive window.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ EXPECT_EQ(kClientIFCW,
+ session->config()->ReceivedInitialFlowControlWindowBytes());
+ server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, DifferentFlowControlWindowsQ020) {
+ // TODO(rjshade): Rename to DifferentFlowControlWindows when removing
+ // QUIC_VERSION_19.
+ // Client and server can set different initial flow control receive windows.
+ // These are sent in CHLO/SHLO. Tests that these values are exchanged properly
+ // in the crypto handshake.
+ const uint32 kClientStreamIFCW = 123456;
+ const uint32 kClientSessionIFCW = 234567;
+ set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
+ set_client_initial_session_flow_control_receive_window(kClientSessionIFCW);
+
+ const uint32 kServerStreamIFCW = 654321;
+ const uint32 kServerSessionIFCW = 765432;
+ set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW);
+ set_server_initial_session_flow_control_receive_window(kServerSessionIFCW);
+
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ <= QUIC_VERSION_19) {
+ return;
+ }
+
+ // Values are exchanged during crypto handshake, so wait for that to finish.
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+
+ // Open a data stream to make sure the stream level flow control is updated.
+ QuicSpdyClientStream* stream = client_->GetOrCreateStream();
+ stream->SendBody("hello", false);
+
+ // Client should have the right values for server's receive window.
+ EXPECT_EQ(kServerStreamIFCW,
+ client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kServerSessionIFCW,
+ client_->client()
+ ->session()
+ ->config()
+ ->ReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ stream->flow_controller()));
+ EXPECT_EQ(kServerSessionIFCW,
+ QuicFlowControllerPeer::SendWindowOffset(
+ client_->client()->session()->flow_controller()));
+
+ // Server should have the right values for client's receive window.
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* session = dispatcher->session_map().begin()->second;
+ EXPECT_EQ(kClientStreamIFCW,
+ session->config()->ReceivedInitialStreamFlowControlWindowBytes());
+ EXPECT_EQ(kClientSessionIFCW,
+ session->config()->ReceivedInitialSessionFlowControlWindowBytes());
+ EXPECT_EQ(kClientSessionIFCW, QuicFlowControllerPeer::SendWindowOffset(
+ session->flow_controller()));
+ server_thread_->Resume();
+}
+
} // namespace
} // namespace test
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_client.cc b/chromium/net/tools/quic/quic_client.cc
index dcf9612a38f..19e98013af2 100644
--- a/chromium/net/tools/quic/quic_client.cc
+++ b/chromium/net/tools/quic/quic_client.cc
@@ -12,11 +12,14 @@
#include <unistd.h>
#include "base/logging.h"
+#include "net/quic/congestion_control/tcp_receiver.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_data_reader.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_server_id.h"
#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
@@ -31,12 +34,14 @@ namespace tools {
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
QuicClient::QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response)
+ bool print_response,
+ EpollServer* epoll_server)
: server_address_(server_address),
- server_hostname_(server_hostname),
+ server_id_(server_id),
local_port_(0),
+ epoll_server_(epoll_server),
fd_(-1),
helper_(CreateQuicConnectionHelper()),
initialized_(false),
@@ -48,20 +53,23 @@ QuicClient::QuicClient(IPEndPoint server_address,
}
QuicClient::QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ bool print_response,
const QuicConfig& config,
- const QuicVersionVector& supported_versions)
+ EpollServer* epoll_server)
: server_address_(server_address),
- server_hostname_(server_hostname),
+ server_id_(server_id),
config_(config),
local_port_(0),
+ epoll_server_(epoll_server),
fd_(-1),
helper_(CreateQuicConnectionHelper()),
initialized_(false),
packets_dropped_(0),
overflow_supported_(false),
supported_versions_(supported_versions),
- print_response_(false) {
+ print_response_(print_response) {
}
QuicClient::~QuicClient() {
@@ -69,14 +77,27 @@ QuicClient::~QuicClient() {
session()->connection()->SendConnectionClosePacket(
QUIC_PEER_GOING_AWAY, "");
}
+ if (fd_ > 0) {
+ epoll_server_->UnregisterFD(fd_);
+ }
}
bool QuicClient::Initialize() {
DCHECK(!initialized_);
- epoll_server_.set_timeout_in_us(50 * 1000);
+ epoll_server_->set_timeout_in_us(50 * 1000);
crypto_config_.SetDefaults();
+ if (!CreateUDPSocket()) {
+ return false;
+ }
+
+ epoll_server_->RegisterFD(fd_, this, kEpollFlags);
+ initialized_ = true;
+ return true;
+}
+
+bool QuicClient::CreateUDPSocket() {
int address_family = server_address_.GetSockAddrFamily();
fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
if (fd_ < 0) {
@@ -93,6 +114,16 @@ bool QuicClient::Initialize() {
overflow_supported_ = true;
}
+ if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
+ if (!QuicSocketUtils::SetSendBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
int get_local_ip = 1;
if (address_family == AF_INET) {
rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
@@ -137,8 +168,6 @@ bool QuicClient::Initialize() {
LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
}
- epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- initialized_ = true;
return true;
}
@@ -153,7 +182,8 @@ bool QuicClient::Connect() {
}
bool QuicClient::StartConnect() {
- DCHECK(!connected() && initialized_);
+ DCHECK(initialized_);
+ DCHECK(!connected());
QuicPacketWriter* writer = CreateQuicPacketWriter();
if (writer_.get() != writer) {
@@ -161,9 +191,9 @@ bool QuicClient::StartConnect() {
}
session_.reset(new QuicClientSession(
- server_hostname_,
+ server_id_,
config_,
- new QuicConnection(GenerateGuid(), server_address_, helper_.get(),
+ new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
writer_.get(), false, supported_versions_),
&crypto_config_));
return session_->CryptoConnect();
@@ -180,23 +210,24 @@ void QuicClient::Disconnect() {
if (connected()) {
session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
}
- epoll_server_.UnregisterFD(fd_);
+ epoll_server_->UnregisterFD(fd_);
close(fd_);
fd_ = -1;
initialized_ = false;
}
void QuicClient::SendRequestsAndWaitForResponse(
- const CommandLine::StringVector& args) {
+ const base::CommandLine::StringVector& args) {
for (size_t i = 0; i < args.size(); ++i) {
BalsaHeaders headers;
headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
QuicSpdyClientStream* stream = CreateReliableClientStream();
+ DCHECK(stream != NULL);
stream->SendRequest(headers, "", true);
stream->set_visitor(this);
}
- while (WaitForEvents()) { }
+ while (WaitForEvents()) {}
}
QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
@@ -210,23 +241,23 @@ QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
void QuicClient::WaitForStreamToClose(QuicStreamId id) {
DCHECK(connected());
- while (!session_->IsClosedStream(id)) {
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ while (connected() && !session_->IsClosedStream(id)) {
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
}
void QuicClient::WaitForCryptoHandshakeConfirmed() {
DCHECK(connected());
- while (!session_->IsCryptoHandshakeConfirmed()) {
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
}
bool QuicClient::WaitForEvents() {
DCHECK(connected());
- epoll_server_.WaitForEventsAndExecuteCallbacks();
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
return session_->num_active_requests() != 0;
}
@@ -238,20 +269,26 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
}
}
if (connected() && (event->in_events & EPOLLOUT)) {
+ writer_->SetWritable();
session_->connection()->OnCanWrite();
}
if (event->in_events & EPOLLERR) {
- DLOG(INFO) << "Epollerr";
+ DVLOG(1) << "Epollerr";
}
}
void QuicClient::OnClose(QuicDataStream* stream) {
+ QuicSpdyClientStream* client_stream =
+ static_cast<QuicSpdyClientStream*>(stream);
+ if (response_listener_.get() != NULL) {
+ response_listener_->OnCompleteResponse(
+ stream->id(), client_stream->headers(), client_stream->data());
+ }
+
if (!print_response_) {
return;
}
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
const BalsaHeaders& headers = client_stream->headers();
printf("%s\n", headers.first_line().as_string().c_str());
for (BalsaHeaders::const_header_lines_iterator i =
@@ -263,30 +300,32 @@ void QuicClient::OnClose(QuicDataStream* stream) {
printf("%s\n", client_stream->data().c_str());
}
-QuicPacketCreator::Options* QuicClient::options() {
- if (session() == NULL) {
- return NULL;
- }
- return session_->options();
-}
-
bool QuicClient::connected() const {
return session_.get() && session_->connection() &&
session_->connection()->connected();
}
-QuicGuid QuicClient::GenerateGuid() {
+QuicConnectionId QuicClient::GenerateConnectionId() {
return QuicRandom::GetInstance()->RandUint64();
}
QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
- return new QuicEpollConnectionHelper(&epoll_server_);
+ return new QuicEpollConnectionHelper(epoll_server_);
}
QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
return new QuicDefaultPacketWriter(fd_);
}
+int QuicClient::ReadPacket(char* buffer,
+ int buffer_len,
+ IPEndPoint* server_address,
+ IPAddressNumber* client_ip) {
+ return QuicSocketUtils::ReadPacket(
+ fd_, buffer, buffer_len, overflow_supported_ ? &packets_dropped_ : NULL,
+ client_ip, server_address);
+}
+
bool QuicClient::ReadAndProcessPacket() {
// Allocate some extra space so we can send an error if the server goes over
// the limit.
@@ -295,27 +334,13 @@ bool QuicClient::ReadAndProcessPacket() {
IPEndPoint server_address;
IPAddressNumber client_ip;
- int bytes_read = QuicSocketUtils::ReadPacket(
- fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
- &client_ip, &server_address);
+ int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
if (bytes_read < 0) {
return false;
}
QuicEncryptedPacket packet(buf, bytes_read, false);
- QuicGuid our_guid = session_->connection()->guid();
- QuicGuid packet_guid;
-
- if (!QuicFramer::ReadGuidFromPacket(packet, &packet_guid)) {
- DLOG(INFO) << "Could not read GUID from packet";
- return true;
- }
- if (packet_guid != our_guid) {
- DLOG(INFO) << "Ignoring packet from unexpected GUID: "
- << packet_guid << " instead of " << our_guid;
- return true;
- }
IPEndPoint client_address(client_ip, client_address_.port());
session_->connection()->ProcessUdpPacket(
diff --git a/chromium/net/tools/quic/quic_client.h b/chromium/net/tools/quic/quic_client.h
index 02f45e6c56a..13aff636ada 100644
--- a/chromium/net/tools/quic/quic_client.h
+++ b/chromium/net/tools/quic/quic_client.h
@@ -10,6 +10,7 @@
#include <string>
+#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
@@ -24,6 +25,7 @@
namespace net {
class ProofVerifier;
+class QuicServerId;
namespace tools {
@@ -36,14 +38,28 @@ class QuicClientPeer;
class QuicClient : public EpollCallbackInterface,
public QuicDataStream::Visitor {
public:
+ class ResponseListener {
+ public:
+ ResponseListener() {}
+ virtual ~ResponseListener() {}
+ virtual void OnCompleteResponse(QuicStreamId id,
+ const BalsaHeaders& response_headers,
+ const string& response_body) = 0;
+ };
+
+ // Create a quic client, which will have events managed by an externally owned
+ // EpollServer.
QuicClient(IPEndPoint server_address,
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response);
+ bool print_response,
+ EpollServer* epoll_server);
QuicClient(IPEndPoint server_address,
- const std::string& server_hostname,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ bool print_response,
const QuicConfig& config,
- const QuicVersionVector& supported_versions);
+ EpollServer* epoll_server);
virtual ~QuicClient();
@@ -69,11 +85,12 @@ class QuicClient : public EpollCallbackInterface,
// Disconnects from the QUIC server.
void Disconnect();
- // Sends a request simple GET for each URL in arg, and then waits for
+ // Sends a request simple GET for each URL in |args|, and then waits for
// each to complete.
- void SendRequestsAndWaitForResponse(const CommandLine::StringVector& args);
+ void SendRequestsAndWaitForResponse(const
+ base::CommandLine::StringVector& args);
- // Returns a newly created CreateReliableClientStream, owned by the
+ // Returns a newly created QuicSpdyClientStream, owned by the
// QuicClient.
QuicSpdyClientStream* CreateReliableClientStream();
@@ -88,8 +105,9 @@ class QuicClient : public EpollCallbackInterface,
bool WaitForEvents();
// From EpollCallbackInterface
- virtual void OnRegistration(
- EpollServer* eps, int fd, int event_mask) OVERRIDE {}
+ virtual void OnRegistration(EpollServer* eps,
+ int fd,
+ int event_mask) OVERRIDE {}
virtual void OnModification(int fd, int event_mask) OVERRIDE {}
virtual void OnEvent(int fd, EpollEvent* event) OVERRIDE;
// |fd_| can be unregistered without the client being disconnected. This
@@ -101,8 +119,6 @@ class QuicClient : public EpollCallbackInterface,
// QuicDataStream::Visitor
virtual void OnClose(QuicDataStream* stream) OVERRIDE;
- QuicPacketCreator::Options* options();
-
QuicClientSession* session() { return session_.get(); }
bool connected() const;
@@ -119,13 +135,19 @@ class QuicClient : public EpollCallbackInterface,
const IPEndPoint& client_address() const { return client_address_; }
- EpollServer* epoll_server() { return &epoll_server_; }
+ EpollServer* epoll_server() { return epoll_server_; }
int fd() { return fd_; }
+ const QuicServerId& server_id() const { return server_id_; }
+
// This should only be set before the initial Connect()
- void set_server_hostname(const string& hostname) {
- server_hostname_ = hostname;
+ void set_server_id(const QuicServerId& server_id) {
+ server_id_ = server_id;
+ }
+
+ void SetUserAgentID(const string& user_agent_id) {
+ crypto_config_.set_user_agent_id(user_agent_id);
}
// SetProofVerifier sets the ProofVerifier that will be used to verify the
@@ -135,29 +157,48 @@ class QuicClient : public EpollCallbackInterface,
crypto_config_.SetProofVerifier(verifier);
}
- // SetChannelIDSigner sets a ChannelIDSigner that will be called when the
- // server supports channel IDs to sign a message proving possession of the
- // given ChannelID. This object takes ownership of |signer|.
- void SetChannelIDSigner(ChannelIDSigner* signer) {
- crypto_config_.SetChannelIDSigner(signer);
+ // SetChannelIDSource sets a ChannelIDSource that will be called, when the
+ // server supports channel IDs, to obtain a channel ID for signing a message
+ // proving possession of the channel ID. This object takes ownership of
+ // |source|.
+ void SetChannelIDSource(ChannelIDSource* source) {
+ crypto_config_.SetChannelIDSource(source);
+ }
+
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ supported_versions_ = versions;
+ }
+
+ // Takes ownership of the listener.
+ void set_response_listener(ResponseListener* listener) {
+ response_listener_.reset(listener);
}
protected:
- virtual QuicGuid GenerateGuid();
+ virtual QuicConnectionId GenerateConnectionId();
virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper();
virtual QuicPacketWriter* CreateQuicPacketWriter();
+ virtual int ReadPacket(char* buffer,
+ int buffer_len,
+ IPEndPoint* server_address,
+ IPAddressNumber* client_ip);
+
private:
friend class net::tools::test::QuicClientPeer;
+ // Used during initialization: creates the UDP socket FD, sets socket options,
+ // and binds the socket to our address.
+ bool CreateUDPSocket();
+
// Read a UDP packet and hand it to the framer.
bool ReadAndProcessPacket();
// Address of the server.
const IPEndPoint server_address_;
- // Hostname of the server. This may be a DNS name or an IP address literal.
- std::string server_hostname_;
+ // |server_id_| is a tuple (hostname, port, is_https) of the server.
+ QuicServerId server_id_;
// config_ and crypto_config_ contain configuration and cached state about
// servers.
@@ -175,13 +216,16 @@ class QuicClient : public EpollCallbackInterface,
// Session which manages streams.
scoped_ptr<QuicClientSession> session_;
// Listens for events on the client socket.
- EpollServer epoll_server_;
+ EpollServer* epoll_server_;
// UDP socket.
int fd_;
// Helper to be used by created connections.
scoped_ptr<QuicEpollConnectionHelper> helper_;
+ // Listens for full responses.
+ scoped_ptr<ResponseListener> response_listener_;
+
// Writer used to actually send packets to the wire.
scoped_ptr<QuicPacketWriter> writer_;
@@ -191,7 +235,7 @@ class QuicClient : public EpollCallbackInterface,
// If overflow_supported_ is true, this will be the number of packets dropped
// during the lifetime of the server. This may overflow if enough packets
// are dropped.
- int packets_dropped_;
+ uint32 packets_dropped_;
// True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
// because the socket would otherwise overflow.
diff --git a/chromium/net/tools/quic/quic_client_bin.cc b/chromium/net/tools/quic/quic_client_bin.cc
index 2f8cfac1736..f743a7dc127 100644
--- a/chromium/net/tools/quic/quic_client_bin.cc
+++ b/chromium/net/tools/quic/quic_client_bin.cc
@@ -4,6 +4,11 @@
// A binary wrapper for QuicClient. Connects to --hostname via --address
// on --port and requests URLs specified on the command line.
+// Pass --secure to check the certificates using proof verifier.
+// Pass --initial_stream_flow_control_window to specify the size of the initial
+// stream flow control receive window to advertise to server.
+// Pass --initial_session_flow_control_window to specify the size of the initial
+// session flow control receive window to advertise to server.
//
// For example:
// quic_client --address=127.0.0.1 --port=6122 --hostname=www.google.com
@@ -16,16 +21,34 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/privacy_mode.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_server_id.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
+// The port the quic client will connect to.
int32 FLAGS_port = 6121;
std::string FLAGS_address = "127.0.0.1";
+// The hostname the quic client will connect to.
std::string FLAGS_hostname = "localhost";
+// Size of the initial stream flow control receive window to advertise to
+// server.
+int32 FLAGS_initial_stream_flow_control_window = 100 * net::kMaxPacketSize;
+// Size of the initial session flow control receive window to advertise to
+// server.
+int32 FLAGS_initial_session_flow_control_window = 200 * net::kMaxPacketSize;
+// Check the certificates using proof verifier.
+bool FLAGS_secure = false;
int main(int argc, char *argv[]) {
- CommandLine::Init(argc, argv);
- CommandLine* line = CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* line = base::CommandLine::ForCurrentProcess();
+
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ CHECK(logging::InitLogging(settings));
+
if (line->HasSwitch("h") || line->HasSwitch("help")) {
const char* help_str =
"Usage: quic_client [options]\n"
@@ -34,7 +57,8 @@ int main(int argc, char *argv[]) {
"-h, --help show this help message and exit\n"
"--port=<port> specify the port to connect to\n"
"--address=<address> specify the IP address to connect to\n"
- "--host=<host> specify the SNI hostname to use\n";
+ "--host=<host> specify the SNI hostname to use\n"
+ "--secure check certificates\n";
std::cout << help_str;
exit(0);
}
@@ -50,18 +74,35 @@ int main(int argc, char *argv[]) {
if (line->HasSwitch("hostname")) {
FLAGS_hostname = line->GetSwitchValueASCII("hostname");
}
- LOG(INFO) << "server port: " << FLAGS_port
- << " address: " << FLAGS_address
- << " hostname: " << FLAGS_hostname;
+ if (line->HasSwitch("secure")) {
+ FLAGS_secure = true;
+ }
+ VLOG(1) << "server port: " << FLAGS_port
+ << " address: " << FLAGS_address
+ << " hostname: " << FLAGS_hostname
+ << " secure: " << FLAGS_secure;
base::AtExitManager exit_manager;
net::IPAddressNumber addr;
CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
+
+ net::QuicConfig config;
+ config.SetDefaults();
+ config.SetInitialFlowControlWindowToSend(
+ FLAGS_initial_session_flow_control_window);
+ config.SetInitialStreamFlowControlWindowToSend(
+ FLAGS_initial_stream_flow_control_window);
+ config.SetInitialSessionFlowControlWindowToSend(
+ FLAGS_initial_session_flow_control_window);
+
// TODO(rjshade): Set version on command line.
+ net::EpollServer epoll_server;
net::tools::QuicClient client(
- net::IPEndPoint(addr, FLAGS_port), FLAGS_hostname,
- net::QuicSupportedVersions(), true);
+ net::IPEndPoint(addr, FLAGS_port),
+ net::QuicServerId(FLAGS_hostname, FLAGS_port, FLAGS_secure,
+ net::PRIVACY_MODE_DISABLED),
+ net::QuicSupportedVersions(), true, config, &epoll_server);
client.Initialize();
diff --git a/chromium/net/tools/quic/quic_client_session.cc b/chromium/net/tools/quic/quic_client_session.cc
index 5bcf6f201f4..aca5418ac37 100644
--- a/chromium/net/tools/quic/quic_client_session.cc
+++ b/chromium/net/tools/quic/quic_client_session.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_server_id.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
using std::string;
@@ -14,30 +15,38 @@ namespace net {
namespace tools {
QuicClientSession::QuicClientSession(
- const string& server_hostname,
+ const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
QuicCryptoClientConfig* crypto_config)
- : QuicSession(connection, config),
- crypto_stream_(server_hostname, this, crypto_config) {
+ : QuicClientSessionBase(connection, config),
+ crypto_stream_(server_id, this, NULL, crypto_config) {
}
QuicClientSession::~QuicClientSession() {
}
+void QuicClientSession::OnProofValid(
+ const QuicCryptoClientConfig::CachedState& /*cached*/) {
+}
+
+void QuicClientSession::OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& /*verify_details*/) {
+}
+
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
if (!crypto_stream_.encryption_established()) {
- DLOG(INFO) << "Encryption not active so no outgoing stream created.";
+ DVLOG(1) << "Encryption not active so no outgoing stream created.";
return NULL;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
- DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumOpenStreams() << " open.";
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already " << GetNumOpenStreams() << " open.";
return NULL;
}
if (goaway_received()) {
- DLOG(INFO) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already received goaway.";
return NULL;
}
QuicSpdyClientStream* stream
diff --git a/chromium/net/tools/quic/quic_client_session.h b/chromium/net/tools/quic/quic_client_session.h
index dcee15e4275..3aad445fcd2 100644
--- a/chromium/net/tools/quic/quic_client_session.h
+++ b/chromium/net/tools/quic/quic_client_session.h
@@ -9,26 +9,34 @@
#include <string>
+#include "base/basictypes.h"
+#include "net/quic/quic_client_session_base.h"
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
namespace net {
class QuicConnection;
+class QuicServerId;
class ReliableQuicStream;
namespace tools {
-class QuicClientSession : public QuicSession {
+class QuicClientSession : public QuicClientSessionBase {
public:
- QuicClientSession(const std::string& server_hostname,
+ QuicClientSession(const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
QuicCryptoClientConfig* crypto_config);
virtual ~QuicClientSession();
+ // QuicClientSessionBase methods:
+ virtual void OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) OVERRIDE;
+ virtual void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) OVERRIDE;
+
// QuicSession methods:
virtual QuicSpdyClientStream* CreateOutgoingDataStream() OVERRIDE;
virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE;
diff --git a/chromium/net/tools/quic/quic_client_session_test.cc b/chromium/net/tools/quic/quic_client_session_test.cc
index c893c20b5e3..7b50f42ab39 100644
--- a/chromium/net/tools/quic/quic_client_session_test.cc
+++ b/chromium/net/tools/quic/quic_client_session_test.cc
@@ -16,6 +16,7 @@
using net::test::CryptoTestUtils;
using net::test::DefaultQuicConfig;
using net::test::PacketSavingConnection;
+using net::test::SupportedVersions;
using testing::_;
namespace net {
@@ -24,14 +25,20 @@ namespace test {
namespace {
const char kServerHostname[] = "www.example.com";
+const uint16 kPort = 80;
-class ToolsQuicClientSessionTest : public ::testing::Test {
+class ToolsQuicClientSessionTest
+ : public ::testing::TestWithParam<QuicVersion> {
protected:
ToolsQuicClientSessionTest()
- : connection_(new PacketSavingConnection(false)) {
+ : connection_(new PacketSavingConnection(false,
+ SupportedVersions(GetParam()))) {
crypto_config_.SetDefaults();
- session_.reset(new QuicClientSession(kServerHostname, DefaultQuicConfig(),
- connection_, &crypto_config_));
+ session_.reset(new QuicClientSession(
+ QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
+ DefaultQuicConfig(),
+ connection_,
+ &crypto_config_));
session_->config()->SetDefaults();
}
@@ -46,11 +53,14 @@ class ToolsQuicClientSessionTest : public ::testing::Test {
QuicCryptoClientConfig crypto_config_;
};
-TEST_F(ToolsQuicClientSessionTest, CryptoConnect) {
+INSTANTIATE_TEST_CASE_P(Tests, ToolsQuicClientSessionTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(ToolsQuicClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
}
-TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
+TEST_P(ToolsQuicClientSessionTest, MaxNumStreams) {
session_->config()->set_max_streams_per_connection(1, 1);
// FLAGS_max_streams_per_connection = 1;
// Initialize crypto before the client session will create a stream.
@@ -67,7 +77,7 @@ TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
EXPECT_TRUE(stream);
}
-TEST_F(ToolsQuicClientSessionTest, GoAwayReceived) {
+TEST_P(ToolsQuicClientSessionTest, GoAwayReceived) {
CompleteCryptoHandshake();
// After receiving a GoAway, I should no longer be able to create outgoing
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.cc b/chromium/net/tools/quic/quic_default_packet_writer.cc
index 9d3e30831c1..84f118aee00 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.cc
+++ b/chromium/net/tools/quic/quic_default_packet_writer.cc
@@ -9,22 +9,37 @@
namespace net {
namespace tools {
-QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd) : fd_(fd) {}
+QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd)
+ : fd_(fd),
+ write_blocked_(false) {}
QuicDefaultPacketWriter::~QuicDefaultPacketWriter() {}
WriteResult QuicDefaultPacketWriter::WritePacket(
- const char* buffer, size_t buf_len,
- const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) {
- return QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
- self_address, peer_address);
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) {
+ DCHECK(!IsWriteBlocked());
+ WriteResult result = QuicSocketUtils::WritePacket(
+ fd_, buffer, buf_len, self_address, peer_address);
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ write_blocked_ = true;
+ }
+ return result;
}
bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const {
return false;
}
+bool QuicDefaultPacketWriter::IsWriteBlocked() const {
+ return write_blocked_;
+}
+
+void QuicDefaultPacketWriter::SetWritable() {
+ write_blocked_ = false;
+}
+
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.h b/chromium/net/tools/quic/quic_default_packet_writer.h
index 20f5fb0db61..7b5a36bdce1 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.h
+++ b/chromium/net/tools/quic/quic_default_packet_writer.h
@@ -11,7 +11,6 @@
namespace net {
-class QuicBlockedWriterInterface;
struct WriteResult;
namespace tools {
@@ -23,15 +22,27 @@ class QuicDefaultPacketWriter : public QuicPacketWriter {
virtual ~QuicDefaultPacketWriter();
// QuicPacketWriter
- virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
- const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+ virtual WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) OVERRIDE;
virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual bool IsWriteBlocked() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
+
+ void set_fd(int fd) { fd_ = fd; }
+
+ protected:
+ void set_write_blocked(bool is_blocked) {
+ write_blocked_ = is_blocked;
+ }
+ int fd() { return fd_; }
private:
int fd_;
+ bool write_blocked_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicDefaultPacketWriter);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_dispatcher.cc b/chromium/net/tools/quic/quic_dispatcher.cc
index 297234d9755..b873f98618a 100644
--- a/chromium/net/tools/quic/quic_dispatcher.cc
+++ b/chromium/net/tools/quic/quic_dispatcher.cc
@@ -6,17 +6,23 @@
#include <errno.h>
+#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_default_packet_writer.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
+#include "net/tools/quic/quic_time_wait_list_manager.h"
namespace net {
+
namespace tools {
+using base::StringPiece;
using std::make_pair;
class DeleteSessionsAlarm : public EpollAlarm {
@@ -35,22 +41,140 @@ class DeleteSessionsAlarm : public EpollAlarm {
QuicDispatcher* dispatcher_;
};
+class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface {
+ public:
+ explicit QuicFramerVisitor(QuicDispatcher* dispatcher)
+ : dispatcher_(dispatcher),
+ connection_id_(0) {}
+
+ // QuicFramerVisitorInterface implementation
+ virtual void OnPacket() OVERRIDE {}
+ virtual bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) OVERRIDE {
+ connection_id_ = header.connection_id;
+ return dispatcher_->OnUnauthenticatedPublicHeader(header);
+ }
+ virtual bool OnUnauthenticatedHeader(
+ const QuicPacketHeader& header) OVERRIDE {
+ dispatcher_->OnUnauthenticatedHeader(header);
+ return false;
+ }
+ virtual void OnError(QuicFramer* framer) OVERRIDE {
+ DVLOG(1) << QuicUtils::ErrorToString(framer->error());
+ }
+
+ virtual bool OnProtocolVersionMismatch(
+ QuicVersion /*received_version*/) OVERRIDE {
+ if (dispatcher_->time_wait_list_manager()->IsConnectionIdInTimeWait(
+ connection_id_)) {
+ // Keep processing after protocol mismatch - this will be dealt with by
+ // the TimeWaitListManager.
+ return true;
+ } else {
+ DLOG(DFATAL) << "Version mismatch, connection ID (" << connection_id_
+ << ") not in time wait list.";
+ return false;
+ }
+ }
+
+ // The following methods should never get called because we always return
+ // false from OnUnauthenticatedHeader(). As a result, we never process the
+ // payload of the packet.
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& /*packet*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnDecryptedPacket(EncryptionLevel level) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual bool OnPacketHeader(const QuicPacketHeader& /*header*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual void OnRevivedPacket() OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnFecProtectedPayload(StringPiece /*payload*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnCongestionFeedbackFrame(
+ const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnStopWaitingFrame(
+ const QuicStopWaitingFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnPingFrame(const QuicPingFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame & /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/)
+ OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+ virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE {
+ DCHECK(false);
+ }
+ virtual void OnPacketComplete() OVERRIDE {
+ DCHECK(false);
+ }
+
+ private:
+ QuicDispatcher* dispatcher_;
+
+ // Latched in OnUnauthenticatedPublicHeader for use later.
+ QuicConnectionId connection_id_;
+};
+
QuicDispatcher::QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- int fd,
EpollServer* epoll_server)
: config_(config),
crypto_config_(crypto_config),
- time_wait_list_manager_(
- new QuicTimeWaitListManager(this, epoll_server, supported_versions)),
delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
epoll_server_(epoll_server),
- fd_(fd),
- write_blocked_(false),
helper_(new QuicEpollConnectionHelper(epoll_server_)),
- writer_(new QuicDefaultPacketWriter(fd)),
- supported_versions_(supported_versions) {
+ supported_versions_(supported_versions),
+ supported_versions_no_flow_control_(supported_versions),
+ supported_versions_no_connection_flow_control_(supported_versions),
+ current_packet_(NULL),
+ framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
+ framer_visitor_(new QuicFramerVisitor(this)) {
+ framer_.set_visitor(framer_visitor_.get());
}
QuicDispatcher::~QuicDispatcher() {
@@ -58,89 +182,121 @@ QuicDispatcher::~QuicDispatcher() {
STLDeleteElements(&closed_session_list_);
}
-void QuicDispatcher::set_fd(int fd) {
- fd_ = fd;
- writer_.reset(new QuicDefaultPacketWriter(fd));
-}
+void QuicDispatcher::Initialize(int fd) {
+ DCHECK(writer_ == NULL);
+ writer_.reset(CreateWriter(fd));
+ time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
-WriteResult QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
- const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* writer) {
- if (write_blocked_) {
- write_blocked_list_.insert(make_pair(writer, true));
- return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+ // Remove all versions > QUIC_VERSION_16 from the
+ // supported_versions_no_flow_control_ vector.
+ QuicVersionVector::iterator it =
+ find(supported_versions_no_flow_control_.begin(),
+ supported_versions_no_flow_control_.end(), QUIC_VERSION_17);
+ if (it != supported_versions_no_flow_control_.end()) {
+ supported_versions_no_flow_control_.erase(
+ supported_versions_no_flow_control_.begin(), it + 1);
}
+ CHECK(!supported_versions_no_flow_control_.empty());
- WriteResult result =
- writer_->WritePacket(buffer, buf_len, self_address, peer_address, writer);
- if (result.status == WRITE_STATUS_BLOCKED) {
- write_blocked_list_.insert(make_pair(writer, true));
- write_blocked_ = true;
+ // Remove all versions > QUIC_VERSION_18 from the
+ // supported_versions_no_connection_flow_control_ vector.
+ QuicVersionVector::iterator connection_it = find(
+ supported_versions_no_connection_flow_control_.begin(),
+ supported_versions_no_connection_flow_control_.end(), QUIC_VERSION_19);
+ if (connection_it != supported_versions_no_connection_flow_control_.end()) {
+ supported_versions_no_connection_flow_control_.erase(
+ supported_versions_no_connection_flow_control_.begin(),
+ connection_it + 1);
}
- return result;
-}
-
-bool QuicDispatcher::IsWriteBlockedDataBuffered() const {
- return writer_->IsWriteBlockedDataBuffered();
+ CHECK(!supported_versions_no_connection_flow_control_.empty());
}
void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet) {
+ current_server_address_ = server_address;
+ current_client_address_ = client_address;
+ current_packet_ = &packet;
+ // ProcessPacket will cause the packet to be dispatched in
+ // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
+ // in OnAuthenticatedHeader.
+ framer_.ProcessPacket(packet);
+ // TODO(rjshade): Return a status describing if/why a packet was dropped,
+ // and log somehow. Maybe expose as a varz.
+}
+
+bool QuicDispatcher::OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) {
QuicSession* session = NULL;
- SessionMap::iterator it = session_map_.find(guid);
+ QuicConnectionId connection_id = header.connection_id;
+ SessionMap::iterator it = session_map_.find(connection_id);
if (it == session_map_.end()) {
- if (time_wait_list_manager_->IsGuidInTimeWait(guid)) {
- time_wait_list_manager_->ProcessPacket(server_address,
- client_address,
- guid,
- packet);
- return;
+ if (header.reset_flag) {
+ return false;
+ }
+ if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
+ return HandlePacketForTimeWait(header);
}
// Ensure the packet has a version negotiation bit set before creating a new
// session for it. All initial packets for a new connection are required to
// have the flag set. Otherwise it may be a stray packet.
- if (has_version_flag) {
- session = CreateQuicSession(guid, server_address, client_address);
+ if (header.version_flag) {
+ session = CreateQuicSession(connection_id, current_server_address_,
+ current_client_address_);
}
if (session == NULL) {
- DLOG(INFO) << "Failed to create session for " << guid;
- // Add this guid fo the time-wait state, to safely reject future packets.
- // We don't know the version here, so assume latest.
- // TODO(ianswett): Produce a no-version version negotiation packet.
- time_wait_list_manager_->AddGuidToTimeWait(guid,
- supported_versions_.front(),
- NULL);
- time_wait_list_manager_->ProcessPacket(server_address,
- client_address,
- guid,
- packet);
- return;
+ DVLOG(1) << "Failed to create session for " << connection_id;
+ // Add this connection_id fo the time-wait state, to safely reject future
+ // packets.
+
+ if (header.version_flag &&
+ !framer_.IsSupportedVersion(header.versions.front())) {
+ // TODO(ianswett): Produce a no-version version negotiation packet.
+ return false;
+ }
+
+ // Use the version in the packet if possible, otherwise assume the latest.
+ QuicVersion version = header.version_flag ? header.versions.front() :
+ supported_versions_.front();
+ time_wait_list_manager_->AddConnectionIdToTimeWait(
+ connection_id, version, NULL);
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+ return HandlePacketForTimeWait(header);
}
- DLOG(INFO) << "Created new session for " << guid;
- session_map_.insert(make_pair(guid, session));
+ DVLOG(1) << "Created new session for " << connection_id;
+ session_map_.insert(make_pair(connection_id, session));
} else {
session = it->second;
}
session->connection()->ProcessUdpPacket(
- server_address, client_address, packet);
+ current_server_address_, current_client_address_, *current_packet_);
+
+ // Do not parse the packet further. The session will process it completely.
+ return false;
+}
+
+void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
+ header.public_header.connection_id));
+ time_wait_list_manager_->ProcessPacket(current_server_address_,
+ current_client_address_,
+ header.public_header.connection_id,
+ header.packet_sequence_number,
+ *current_packet_);
}
void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
QuicConnection* connection = it->second->connection();
QuicEncryptedPacket* connection_close_packet =
- connection->ReleaseConnectionClosePacket();
+ connection->ReleaseConnectionClosePacket();
write_blocked_list_.erase(connection);
- time_wait_list_manager_->AddGuidToTimeWait(it->first,
- connection->version(),
- connection_close_packet);
+ time_wait_list_manager_->AddConnectionIdToTimeWait(it->first,
+ connection->version(),
+ connection_close_packet);
session_map_.erase(it);
}
@@ -148,37 +304,29 @@ void QuicDispatcher::DeleteSessions() {
STLDeleteElements(&closed_session_list_);
}
-void QuicDispatcher::UseWriter(QuicPacketWriter* writer) {
- writer_.reset(writer);
-}
-
-bool QuicDispatcher::OnCanWrite() {
+void QuicDispatcher::OnCanWrite() {
// We got an EPOLLOUT: the socket should not be blocked.
- write_blocked_ = false;
+ writer_->SetWritable();
// Give each writer one attempt to write.
int num_writers = write_blocked_list_.size();
for (int i = 0; i < num_writers; ++i) {
if (write_blocked_list_.empty()) {
- break;
+ return;
}
- QuicBlockedWriterInterface* writer = write_blocked_list_.begin()->first;
+ QuicBlockedWriterInterface* blocked_writer =
+ write_blocked_list_.begin()->first;
write_blocked_list_.erase(write_blocked_list_.begin());
- bool can_write_more = writer->OnCanWrite();
- if (write_blocked_) {
- // We were unable to write. Wait for the next EPOLLOUT.
- // In this case, the session would have been added to the blocked list
- // up in WritePacket.
- return false;
- }
- // The socket is not blocked but the writer has ceded work. Add it to the
- // end of the list.
- if (can_write_more) {
- write_blocked_list_.insert(make_pair(writer, true));
+ blocked_writer->OnCanWrite();
+ if (writer_->IsWriteBlocked()) {
+ // We were unable to write. Wait for the next EPOLLOUT. The writer is
+ // responsible for adding itself to the blocked list via OnWriteBlocked().
+ return;
}
}
+}
- // We're not write blocked. Return true if there's more work to do.
+bool QuicDispatcher::HasPendingWrites() const {
return !write_blocked_list_.empty();
}
@@ -192,15 +340,19 @@ void QuicDispatcher::Shutdown() {
DeleteSessions();
}
-void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) {
- SessionMap::iterator it = session_map_.find(guid);
+void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) {
+ SessionMap::iterator it = session_map_.find(connection_id);
if (it == session_map_.end()) {
- LOG(DFATAL) << "GUID " << guid << " does not exist in the session map. "
+ LOG(DFATAL) << "ConnectionId " << connection_id
+ << " does not exist in the session map. "
<< "Error: " << QuicUtils::ErrorToString(error);
+ LOG(DFATAL) << base::debug::StackTrace().ToString();
return;
}
- DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection (" << guid
+ DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection ("
+ << connection_id
<< ") due to error: "
<< QuicUtils::ErrorToString(error);
@@ -212,16 +364,75 @@ void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) {
CleanUpSession(it);
}
+void QuicDispatcher::OnWriteBlocked(QuicBlockedWriterInterface* writer) {
+ DCHECK(writer_->IsWriteBlocked());
+ write_blocked_list_.insert(make_pair(writer, true));
+}
+
+QuicPacketWriter* QuicDispatcher::CreateWriter(int fd) {
+ return new QuicDefaultPacketWriter(fd);
+}
+
QuicSession* QuicDispatcher::CreateQuicSession(
- QuicGuid guid,
+ QuicConnectionId connection_id,
const IPEndPoint& server_address,
const IPEndPoint& client_address) {
QuicServerSession* session = new QuicServerSession(
- config_, new QuicConnection(guid, client_address, helper_.get(), this,
- true, supported_versions_), this);
+ config_,
+ CreateQuicConnection(connection_id, server_address, client_address),
+ this);
session->InitializeSession(crypto_config_);
return session;
}
+QuicConnection* QuicDispatcher::CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address) {
+ if (FLAGS_enable_quic_stream_flow_control_2 &&
+ FLAGS_enable_quic_connection_flow_control_2) {
+ DLOG(INFO) << "Creating QuicDispatcher with all versions.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true, supported_versions_);
+ }
+
+ if (FLAGS_enable_quic_stream_flow_control_2 &&
+ !FLAGS_enable_quic_connection_flow_control_2) {
+ DLOG(INFO) << "Connection flow control disabled, creating QuicDispatcher "
+ << "WITHOUT version 19 or higher.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true,
+ supported_versions_no_connection_flow_control_);
+ }
+
+ DLOG(INFO) << "Flow control disabled, creating QuicDispatcher WITHOUT "
+ << "version 17 or higher.";
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true,
+ supported_versions_no_flow_control_);
+}
+
+QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
+ return new QuicTimeWaitListManager(
+ writer_.get(), this, epoll_server(), supported_versions());
+}
+
+bool QuicDispatcher::HandlePacketForTimeWait(
+ const QuicPacketPublicHeader& header) {
+ if (header.reset_flag) {
+ // Public reset packets do not have sequence numbers, so ignore the packet.
+ return false;
+ }
+
+ // Switch the framer to the correct version, so that the sequence number can
+ // be parsed correctly.
+ framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId(
+ header.connection_id));
+
+ // Continue parsing the packet to extract the sequence number. Then
+ // send it to the time wait manager in OnUnathenticatedHeader.
+ return true;
+}
+
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/quic_dispatcher.h b/chromium/net/tools/quic/quic_dispatcher.h
index 58a4c0c1423..d60ba69883d 100644
--- a/chromium/net/tools/quic/quic_dispatcher.h
+++ b/chromium/net/tools/quic/quic_dispatcher.h
@@ -10,14 +10,13 @@
#include <list>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
#include "net/base/linked_hash_map.h"
#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_server_session.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
@@ -42,6 +41,8 @@ class QuicSession;
namespace tools {
+class QuicPacketWriterWrapper;
+
namespace test {
class QuicDispatcherPeer;
} // namespace test
@@ -49,7 +50,7 @@ class QuicDispatcherPeer;
class DeleteSessionsAlarm;
class QuicEpollConnectionHelper;
-class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
+class QuicDispatcher : public QuicServerSessionVisitor {
public:
// Ideally we'd have a linked_hash_set: the boolean is unused.
typedef linked_hash_map<QuicBlockedWriterInterface*, bool> WriteBlockedList;
@@ -60,87 +61,134 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- int fd,
EpollServer* epoll_server);
+
virtual ~QuicDispatcher();
- // QuicPacketWriter
- virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
- const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* writer) OVERRIDE;
- virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual void Initialize(int fd);
// Process the incoming packet by creating a new session, passing it to
// an existing session, or passing it to the TimeWaitListManager.
virtual void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet);
- // Called when the underyling connection becomes writable to allow
- // queued writes to happen.
- //
- // Returns true if more writes are possible, false otherwise.
- virtual bool OnCanWrite();
+ // Called when the socket becomes writable to allow queued writes to happen.
+ virtual void OnCanWrite();
+
+ // Returns true if there's anything in the blocked writer list.
+ virtual bool HasPendingWrites() const;
// Sends ConnectionClose frames to all connected clients.
void Shutdown();
+ // QuicServerSessionVisitor interface implementation:
// Ensure that the closed connection is cleaned up asynchronously.
- virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) OVERRIDE;
+ virtual void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) OVERRIDE;
- // Sets the fd and creates a default packet writer with that fd.
- void set_fd(int fd);
+ // Queues the blocked writer for later resumption.
+ virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) OVERRIDE;
- typedef base::hash_map<QuicGuid, QuicSession*> SessionMap;
-
- virtual QuicSession* CreateQuicSession(
- QuicGuid guid,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address);
+ typedef base::hash_map<QuicConnectionId, QuicSession*> SessionMap;
// Deletes all sessions on the closed session list and clears the list.
void DeleteSessions();
const SessionMap& session_map() const { return session_map_; }
- // Uses the specified |writer| instead of QuicSocketUtils and takes ownership
- // of writer.
- void UseWriter(QuicPacketWriter* writer);
-
WriteBlockedList* write_blocked_list() { return &write_blocked_list_; }
protected:
- const QuicConfig& config_;
- const QuicCryptoServerConfig& crypto_config_;
+ // Instantiates a new low-level packet writer. Caller takes ownership of the
+ // returned object.
+ virtual QuicPacketWriter* CreateWriter(int fd);
+
+ virtual QuicSession* CreateQuicSession(QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address);
+
+ virtual QuicConnection* CreateQuicConnection(
+ QuicConnectionId connection_id,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address);
+
+ // Called by |framer_visitor_| when the public header has been parsed.
+ virtual bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header);
+
+ // Create and return the time wait list manager for this dispatcher, which
+ // will be owned by the dispatcher as time_wait_list_manager_
+ virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
+
+ // Replaces the packet writer with |writer|. Takes ownership of |writer|.
+ void set_writer(QuicPacketWriter* writer) {
+ writer_.reset(writer);
+ }
QuicTimeWaitListManager* time_wait_list_manager() {
return time_wait_list_manager_.get();
}
- QuicEpollConnectionHelper* helper() { return helper_.get(); }
EpollServer* epoll_server() { return epoll_server_; }
const QuicVersionVector& supported_versions() const {
return supported_versions_;
}
+ const QuicVersionVector& supported_versions_no_flow_control() const {
+ return supported_versions_no_flow_control_;
+ }
+
+ const QuicVersionVector& supported_versions_no_connection_flow_control()
+ const {
+ return supported_versions_no_connection_flow_control_;
+ }
+
+ const IPEndPoint& current_server_address() {
+ return current_server_address_;
+ }
+ const IPEndPoint& current_client_address() {
+ return current_client_address_;
+ }
+ const QuicEncryptedPacket& current_packet() {
+ return *current_packet_;
+ }
+
+ const QuicConfig& config() const { return config_; }
+
+ const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
+
+ QuicFramer* framer() { return &framer_; }
+
+ QuicEpollConnectionHelper* helper() { return helper_.get(); }
+
+ QuicPacketWriter* writer() { return writer_.get(); }
+
private:
+ class QuicFramerVisitor;
friend class net::tools::test::QuicDispatcherPeer;
+ // Called by |framer_visitor_| when the private header has been parsed
+ // of a data packet that is destined for the time wait manager.
+ void OnUnauthenticatedHeader(const QuicPacketHeader& header);
+
// Removes the session from the session map and write blocked list, and
- // adds the GUID to the time-wait list.
+ // adds the ConnectionId to the time-wait list.
void CleanUpSession(SessionMap::iterator it);
+ bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
+
+ const QuicConfig& config_;
+
+ const QuicCryptoServerConfig& crypto_config_;
+
// The list of connections waiting to write.
WriteBlockedList write_blocked_list_;
SessionMap session_map_;
- // Entity that manages guids in time wait state.
+ // Entity that manages connection_ids in time wait state.
scoped_ptr<QuicTimeWaitListManager> time_wait_list_manager_;
// An alarm which deletes closed sessions.
@@ -151,13 +199,6 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
EpollServer* epoll_server_; // Owned by the server.
- // The connection for client-server communication
- int fd_;
-
- // True if the session is write blocked due to the socket returning EAGAIN.
- // False if we have gotten a call to OnCanWrite after the last failed write.
- bool write_blocked_;
-
// The helper used for all connections.
scoped_ptr<QuicEpollConnectionHelper> helper_;
@@ -170,6 +211,28 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
// skipped as necessary).
const QuicVersionVector supported_versions_;
+ // Versions which do not support flow control (introduced in QUIC_VERSION_17).
+ // This is used to construct new QuicConnections when flow control is disabled
+ // via flag.
+ // TODO(rjshade): Remove this when
+ // FLAGS_enable_quic_stream_flow_control_2 is removed.
+ QuicVersionVector supported_versions_no_flow_control_;
+ // Versions which do not support *connection* flow control (introduced in
+ // QUIC_VERSION_19).
+ // This is used to construct new QuicConnections when connection flow control
+ // is disabled via flag.
+ // TODO(rjshade): Remove this when
+ // FLAGS_enable_quic_connection_flow_control_2 is removed.
+ QuicVersionVector supported_versions_no_connection_flow_control_;
+
+ // Information about the packet currently being handled.
+ IPEndPoint current_client_address_;
+ IPEndPoint current_server_address_;
+ const QuicEncryptedPacket* current_packet_;
+
+ QuicFramer framer_;
+ scoped_ptr<QuicFramerVisitor> framer_visitor_;
+
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/chromium/net/tools/quic/quic_dispatcher_test.cc b/chromium/net/tools/quic/quic_dispatcher_test.cc
index 74cab69e6a7..41c3c27946a 100644
--- a/chromium/net/tools/quic/quic_dispatcher_test.cc
+++ b/chromium/net/tools/quic/quic_dispatcher_test.cc
@@ -11,8 +11,11 @@
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_crypto_stream.h"
+#include "net/quic/quic_flags.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
@@ -21,15 +24,16 @@
using base::StringPiece;
using net::EpollServer;
+using net::test::ConstructEncryptedPacket;
using net::test::MockSession;
+using net::test::ValueRestore;
using net::tools::test::MockConnection;
using std::make_pair;
-using testing::_;
using testing::DoAll;
-using testing::Invoke;
using testing::InSequence;
-using testing::Return;
+using testing::Invoke;
using testing::WithoutArgs;
+using testing::_;
namespace net {
namespace tools {
@@ -41,14 +45,20 @@ class TestDispatcher : public QuicDispatcher {
explicit TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
EpollServer* eps)
- : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), 1, eps) {
+ : QuicDispatcher(config,
+ crypto_config,
+ QuicSupportedVersions(),
+ eps) {
}
MOCK_METHOD3(CreateQuicSession, QuicSession*(
- QuicGuid guid,
+ QuicConnectionId connection_id,
const IPEndPoint& server_address,
const IPEndPoint& client_address));
using QuicDispatcher::write_blocked_list;
+
+ using QuicDispatcher::current_server_address;
+ using QuicDispatcher::current_client_address;
};
// A Connection class which unregisters the session from the dispatcher
@@ -57,30 +67,31 @@ class TestDispatcher : public QuicDispatcher {
// involve a lot more mocking.
class MockServerConnection : public MockConnection {
public:
- MockServerConnection(QuicGuid guid,
+ MockServerConnection(QuicConnectionId connection_id,
QuicDispatcher* dispatcher)
- : MockConnection(guid, true),
- dispatcher_(dispatcher) {
- }
+ : MockConnection(connection_id, true),
+ dispatcher_(dispatcher) {}
+
void UnregisterOnConnectionClosed() {
- LOG(ERROR) << "Unregistering " << guid();
- dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR);
+ LOG(ERROR) << "Unregistering " << connection_id();
+ dispatcher_->OnConnectionClosed(connection_id(), QUIC_NO_ERROR);
}
private:
QuicDispatcher* dispatcher_;
};
QuicSession* CreateSession(QuicDispatcher* dispatcher,
- QuicGuid guid,
- const IPEndPoint& addr,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
MockSession** session) {
- MockServerConnection* connection = new MockServerConnection(guid, dispatcher);
+ MockServerConnection* connection =
+ new MockServerConnection(connection_id, dispatcher);
*session = new MockSession(connection);
ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
WithoutArgs(Invoke(
connection, &MockServerConnection::UnregisterOnConnectionClosed)));
EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()),
- ProcessUdpPacket(_, addr, _));
+ ProcessUdpPacket(_, client_address, _));
return *session;
}
@@ -93,6 +104,7 @@ class QuicDispatcherTest : public ::testing::Test {
dispatcher_(config_, crypto_config_, &eps_),
session1_(NULL),
session2_(NULL) {
+ dispatcher_.Initialize(1);
}
virtual ~QuicDispatcherTest() {}
@@ -105,22 +117,25 @@ class QuicDispatcherTest : public ::testing::Test {
return reinterpret_cast<MockConnection*>(session2_->connection());
}
- void ProcessPacket(IPEndPoint addr,
- QuicGuid guid,
+ void ProcessPacket(IPEndPoint client_address,
+ QuicConnectionId connection_id,
bool has_version_flag,
const string& data) {
- dispatcher_.ProcessPacket(
- IPEndPoint(), addr, guid, has_version_flag,
- QuicEncryptedPacket(data.data(), data.length()));
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ connection_id, has_version_flag, false, 1, data));
+ data_ = string(packet->data(), packet->length());
+ dispatcher_.ProcessPacket(server_address_, client_address, *packet);
}
void ValidatePacket(const QuicEncryptedPacket& packet) {
- EXPECT_TRUE(packet.AsStringPiece().find(data_) != StringPiece::npos);
+ EXPECT_EQ(data_.length(), packet.AsStringPiece().length());
+ EXPECT_EQ(data_, packet.AsStringPiece());
}
EpollServer eps_;
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ IPEndPoint server_address_;
TestDispatcher dispatcher_;
MockSession* session1_;
MockSession* session2_;
@@ -128,34 +143,39 @@ class QuicDispatcherTest : public ::testing::Test {
};
TEST_F(QuicDispatcherTest, ProcessPackets) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ IPAddressNumber any4;
+ CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
+ server_address_ = IPEndPoint(any4, 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
+ EXPECT_EQ(client_address, dispatcher_.current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_.current_server_address());
- EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, addr))
+
+ EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
- data_ = "eep";
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _)).Times(1).
WillOnce(testing::WithArgs<2>(Invoke(
this, &QuicDispatcherTest::ValidatePacket)));
- ProcessPacket(addr, 1, false, "eep");
+ ProcessPacket(client_address, 1, false, "eep");
}
TEST_F(QuicDispatcherTest, Shutdown) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
+ &dispatcher_, 1, client_address, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ ProcessPacket(client_address, 1, true, "foo");
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
SendConnectionClose(QUIC_PEER_GOING_AWAY));
@@ -166,34 +186,36 @@ TEST_F(QuicDispatcherTest, Shutdown) {
class MockTimeWaitListManager : public QuicTimeWaitListManager {
public:
MockTimeWaitListManager(QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* eps)
- : QuicTimeWaitListManager(writer, eps, QuicSupportedVersions()) {
+ : QuicTimeWaitListManager(writer, visitor, eps, QuicSupportedVersions()) {
}
- MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
+ MOCK_METHOD5(ProcessPacket, void(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
const QuicEncryptedPacket& packet));
};
TEST_F(QuicDispatcherTest, TimeWaitListManager) {
MockTimeWaitListManager* time_wait_list_manager =
new MockTimeWaitListManager(
- QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
+ QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_);
// dispatcher takes the ownership of time_wait_list_manager.
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
// Create a new session.
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(guid, _, addr))
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, guid, addr, &session1_)));
- ProcessPacket(addr, guid, true, "foo");
+ &dispatcher_, connection_id, client_address, &session1_)));
+ ProcessPacket(client_address, connection_id, true, "foo");
// Close the connection by sending public reset packet.
QuicPublicResetPacket packet;
- packet.public_header.guid = guid;
+ packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = 19191;
@@ -209,47 +231,117 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
.WillOnce(Invoke(
reinterpret_cast<MockConnection*>(session1_->connection()),
&MockConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), addr, guid, true, *encrypted);
- EXPECT_TRUE(time_wait_list_manager->IsGuidInTimeWait(guid));
-
- // Dispatcher forwards subsequent packets for this guid to the time wait list
- // manager.
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
- ProcessPacket(addr, guid, true, "foo");
+ dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted);
+ EXPECT_TRUE(time_wait_list_manager->IsConnectionIdInTimeWait(connection_id));
+
+ // Dispatcher forwards subsequent packets for this connection_id to the time
+ // wait list manager.
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
+ ProcessPacket(client_address, connection_id, true, "foo");
}
TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) {
MockTimeWaitListManager* time_wait_list_manager =
new MockTimeWaitListManager(
- QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
+ QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_);
// dispatcher takes the ownership of time_wait_list_manager.
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- // Dispatcher forwards all packets for this guid to the time wait list
- // manager.
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ // Dispatcher forwards all packets for this connection_id to the time wait
+ // list manager.
EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
string data = "foo";
- ProcessPacket(addr, guid, false, "foo");
+ ProcessPacket(client_address, connection_id, false, "foo");
+}
+
+TEST(QuicDispatcherFlowControlTest, NoNewVersion17ConnectionsIfFlagDisabled) {
+ // If FLAGS_enable_quic_stream_flow_control_2 is disabled
+ // then the dispatcher should stop creating connections that support
+ // QUIC_VERSION_17 (existing connections will stay alive).
+ // TODO(rjshade): Remove once
+ // FLAGS_enable_quic_stream_flow_control_2 is removed.
+
+ EpollServer eps;
+ QuicConfig config;
+ QuicCryptoServerConfig server_config(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance());
+ IPEndPoint client(net::test::Loopback4(), 1);
+ IPEndPoint server(net::test::Loopback4(), 1);
+ QuicConnectionId kCID = 1234;
+
+ QuicVersion kTestQuicVersions[] = {QUIC_VERSION_17,
+ QUIC_VERSION_16,
+ QUIC_VERSION_15};
+ QuicVersionVector kTestVersions;
+ for (size_t i = 0; i < arraysize(kTestQuicVersions); ++i) {
+ kTestVersions.push_back(kTestQuicVersions[i]);
+ }
+
+ QuicDispatcher dispatcher(config, server_config, kTestVersions, &eps);
+ dispatcher.Initialize(0);
+
+ // When flag is enabled, new connections should support QUIC_VERSION_17.
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
+ scoped_ptr<QuicConnection> connection_1(
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
+ EXPECT_EQ(QUIC_VERSION_17, connection_1->version());
+
+
+ // When flag is disabled, new connections should not support QUIC_VERSION_17.
+ FLAGS_enable_quic_stream_flow_control_2 = false;
+ scoped_ptr<QuicConnection> connection_2(
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
+ EXPECT_EQ(QUIC_VERSION_16, connection_2->version());
}
-class QuicWriteBlockedListTest : public QuicDispatcherTest {
+class BlockingWriter : public QuicPacketWriterWrapper {
+ public:
+ BlockingWriter() : write_blocked_(false) {}
+
+ virtual bool IsWriteBlocked() const OVERRIDE { return write_blocked_; }
+ virtual void SetWritable() OVERRIDE { write_blocked_ = false; }
+
+ virtual WriteResult WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_client_address,
+ const IPEndPoint& peer_client_address) OVERRIDE {
+ if (write_blocked_) {
+ return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+ } else {
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_client_address, peer_client_address);
+ }
+ }
+
+ bool write_blocked_;
+};
+
+class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
public:
virtual void SetUp() {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ writer_ = new BlockingWriter;
+ QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
blocked_list_ = dispatcher_.write_blocked_list();
}
@@ -260,90 +352,105 @@ class QuicWriteBlockedListTest : public QuicDispatcherTest {
dispatcher_.Shutdown();
}
- bool SetBlocked() {
- QuicDispatcherPeer::SetWriteBlocked(&dispatcher_);
- return true;
+ void SetBlocked() {
+ writer_->write_blocked_ = true;
+ }
+
+ void BlockConnection2() {
+ writer_->write_blocked_ = true;
+ dispatcher_.OnWriteBlocked(connection2());
}
protected:
+ BlockingWriter* writer_;
QuicDispatcher::WriteBlockedList* blocked_list_;
};
-TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) {
+TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) {
// No OnCanWrite calls because no connections are blocked.
dispatcher_.OnCanWrite();
- // Register connection 1 for events, and make sure it's nofitied.
- blocked_list_->insert(make_pair(connection1(), true));
+ // Register connection 1 for events, and make sure it's notified.
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite());
dispatcher_.OnCanWrite();
// It should get only one notification.
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- EXPECT_FALSE(dispatcher_.OnCanWrite());
+ dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteOrder) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
// Make sure we handle events in order.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
// Check the other ordering.
- blocked_list_->insert(make_pair(connection2(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
EXPECT_CALL(*connection1(), OnCanWrite());
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteRemove) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) {
// Add and remove one connction.
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
// Add and remove one connction and make sure it doesn't affect others.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
// Add it, remove it, and add it back and make sure things are OK.
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
- blocked_list_->insert(make_pair(connection1(), true));
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, DoubleAdd) {
+TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) {
// Make sure a double add does not necessitate a double remove.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
// Make sure a double add does not result in two OnCanWrite calls.
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection1(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
+TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
- Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
@@ -352,34 +459,41 @@ TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
dispatcher_.OnCanWrite();
}
-TEST_F(QuicWriteBlockedListTest, LimitedWrites) {
+TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
// Make sure we call both writers. The first will register for more writing
// but should not be immediately called due to limits.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
- EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true));
- EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
+ EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// Now call OnCanWrite again, and connection1 should get its second chance
- EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
-TEST_F(QuicWriteBlockedListTest, TestWriteLimits) {
+TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
- blocked_list_->insert(make_pair(connection1(), true));
- blocked_list_->insert(make_pair(connection2(), true));
+ SetBlocked();
+ dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_.OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
- Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_epoll_clock.h b/chromium/net/tools/quic/quic_epoll_clock.h
index fb21354a9e0..d96bff64389 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.h
+++ b/chromium/net/tools/quic/quic_epoll_clock.h
@@ -5,6 +5,7 @@
#ifndef NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_
#define NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_
+#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "net/quic/quic_clock.h"
#include "net/quic/quic_time.h"
@@ -31,6 +32,9 @@ class QuicEpollClock : public QuicClock {
protected:
EpollServer* epoll_server_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicEpollClock);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.cc b/chromium/net/tools/quic/quic_in_memory_cache.cc
index c7c7cd04ebf..af46ca37daa 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache.cc
@@ -99,7 +99,7 @@ void QuicInMemoryCache::AddSimpleResponse(StringPiece method,
void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers,
const BalsaHeaders& response_headers,
StringPiece response_body) {
- LOG(INFO) << "Adding response for: " << GetKey(request_headers);
+ VLOG(1) << "Adding response for: " << GetKey(request_headers);
if (ContainsKey(responses_, GetKey(request_headers))) {
LOG(DFATAL) << "Response for given request already exists!";
return;
@@ -110,6 +110,18 @@ void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers,
responses_[GetKey(request_headers)] = new_response;
}
+void QuicInMemoryCache::AddSpecialResponse(StringPiece method,
+ StringPiece path,
+ StringPiece version,
+ SpecialResponseType response_type) {
+ BalsaHeaders request_headers, response_headers;
+ request_headers.SetRequestFirstlineFromStringPieces(method,
+ path,
+ version);
+ AddResponse(request_headers, response_headers, "");
+ responses_[GetKey(request_headers)]->response_type_ = response_type;
+}
+
QuicInMemoryCache::QuicInMemoryCache() {
Initialize();
}
@@ -122,11 +134,11 @@ void QuicInMemoryCache::ResetForTests() {
void QuicInMemoryCache::Initialize() {
// If there's no defined cache dir, we have no initialization to do.
if (FLAGS_quic_in_memory_cache_dir.empty()) {
- LOG(WARNING) << "No cache directory found. Skipping initialization.";
+ VLOG(1) << "No cache directory found. Skipping initialization.";
return;
}
- LOG(INFO) << "Attempting to initialize QuicInMemoryCache from directory: "
- << FLAGS_quic_in_memory_cache_dir;
+ VLOG(1) << "Attempting to initialize QuicInMemoryCache from directory: "
+ << FLAGS_quic_in_memory_cache_dir;
FilePath directory(FLAGS_quic_in_memory_cache_dir);
base::FileEnumerator file_list(directory,
@@ -199,8 +211,8 @@ void QuicInMemoryCache::Initialize() {
"HTTP/1.1");
request_headers.ReplaceOrAppendHeader("host", host);
- LOG(INFO) << "Inserting 'http://" << GetKey(request_headers)
- << "' into QuicInMemoryCache.";
+ VLOG(1) << "Inserting 'http://" << GetKey(request_headers)
+ << "' into QuicInMemoryCache.";
AddResponse(request_headers, response_headers, caching_visitor.body());
@@ -214,6 +226,9 @@ QuicInMemoryCache::~QuicInMemoryCache() {
string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const {
StringPiece uri = request_headers.request_uri();
+ if (uri.size() == 0) {
+ return "";
+ }
StringPiece host;
if (uri[0] == '/') {
host = request_headers.GetHeader("host");
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.h b/chromium/net/tools/quic/quic_in_memory_cache.h
index 3be25a6cac1..be091d5579e 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.h
+++ b/chromium/net/tools/quic/quic_in_memory_cache.h
@@ -32,12 +32,19 @@ class QuicServer;
// `wget -p --save_headers <url>`
class QuicInMemoryCache {
public:
+ enum SpecialResponseType {
+ REGULAR_RESPONSE, // Send the headers and body like a server should.
+ CLOSE_CONNECTION, // Close the connection (sending the close packet).
+ IGNORE_REQUEST, // Do nothing, expect the client to time out.
+ };
+
// Container for response header/body pairs.
class Response {
public:
- Response() {}
+ Response() : response_type_(REGULAR_RESPONSE) {}
~Response() {}
+ const SpecialResponseType response_type() const { return response_type_; }
const BalsaHeaders& headers() const { return headers_; }
const base::StringPiece body() const { return base::StringPiece(body_); }
@@ -51,6 +58,7 @@ class QuicInMemoryCache {
body.CopyToString(&body_);
}
+ SpecialResponseType response_type_;
BalsaHeaders headers_;
std::string body_;
@@ -79,6 +87,12 @@ class QuicInMemoryCache {
const BalsaHeaders& response_headers,
base::StringPiece response_body);
+ // Simulate a special behavior at a particular path.
+ void AddSpecialResponse(base::StringPiece method,
+ base::StringPiece path,
+ base::StringPiece version,
+ SpecialResponseType response_type);
+
private:
typedef base::hash_map<std::string, Response*> ResponseMap;
friend struct DefaultSingletonTraits<QuicInMemoryCache>;
diff --git a/chromium/net/tools/quic/quic_in_memory_cache_test.cc b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
index adcb59917c5..1d4d24cff9f 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
@@ -39,7 +39,7 @@ class QuicInMemoryCacheTest : public ::testing::Test {
headers->ReplaceOrAppendHeader("host", host);
}
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
QuicInMemoryCachePeer::ResetForTests();
}
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
new file mode 100644
index 00000000000..3d1b03d48e9
--- /dev/null
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -0,0 +1,48 @@
+// Copyright 2014 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 "net/tools/quic/quic_packet_writer_wrapper.h"
+
+#include "net/quic/quic_types.h"
+
+namespace net {
+namespace tools {
+
+QuicPacketWriterWrapper::QuicPacketWriterWrapper() {}
+
+QuicPacketWriterWrapper::QuicPacketWriterWrapper(QuicPacketWriter* writer)
+ : writer_(writer) {}
+
+QuicPacketWriterWrapper::~QuicPacketWriterWrapper() {}
+
+WriteResult QuicPacketWriterWrapper::WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const net::IPAddressNumber& self_address,
+ const net::IPEndPoint& peer_address) {
+ return writer_->WritePacket(buffer, buf_len, self_address, peer_address);
+}
+
+bool QuicPacketWriterWrapper::IsWriteBlockedDataBuffered() const {
+ return writer_->IsWriteBlockedDataBuffered();
+}
+
+bool QuicPacketWriterWrapper::IsWriteBlocked() const {
+ return writer_->IsWriteBlocked();
+}
+
+void QuicPacketWriterWrapper::SetWritable() {
+ writer_->SetWritable();
+}
+
+void QuicPacketWriterWrapper::set_writer(QuicPacketWriter* writer) {
+ writer_.reset(writer);
+}
+
+QuicPacketWriter* QuicPacketWriterWrapper::release_writer() {
+ return writer_.release();
+}
+
+} // namespace tools
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.h b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
new file mode 100644
index 00000000000..9dafe776e24
--- /dev/null
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
@@ -0,0 +1,50 @@
+// Copyright 2014 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.
+
+#ifndef NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
+#define NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/quic_packet_writer.h"
+
+namespace net {
+
+namespace tools {
+
+// Wraps a writer object to allow dynamically extending functionality. Use
+// cases: replace writer while dispatcher and connections hold on to the
+// wrapper; mix in monitoring in internal server; mix in mocks in unit tests.
+class QuicPacketWriterWrapper : public net::QuicPacketWriter {
+ public:
+ QuicPacketWriterWrapper();
+ explicit QuicPacketWriterWrapper(QuicPacketWriter* writer);
+ virtual ~QuicPacketWriterWrapper();
+
+ // Default implementation of the QuicPacketWriter interface. Passes everything
+ // to |writer_|.
+ virtual WriteResult WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_address,
+ const IPEndPoint& peer_address) OVERRIDE;
+ virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual bool IsWriteBlocked() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
+
+ // Takes ownership of |writer|.
+ void set_writer(QuicPacketWriter* writer);
+
+ // Releases ownership of |writer_|.
+ QuicPacketWriter* release_writer();
+
+ private:
+ scoped_ptr<QuicPacketWriter> writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicPacketWriterWrapper);
+};
+
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_
diff --git a/chromium/net/tools/quic/quic_server.cc b/chromium/net/tools/quic/quic_server.cc
index a62cfbbdf15..be3d9fbd128 100644
--- a/chromium/net/tools/quic/quic_server.cc
+++ b/chromium/net/tools/quic/quic_server.cc
@@ -12,6 +12,7 @@
#include <sys/socket.h>
#include "net/base/ip_endpoint.h"
+#include "net/quic/congestion_control/tcp_receiver.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_clock.h"
@@ -29,6 +30,7 @@
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
static const char kSourceAddressTokenSecret[] = "secret";
+const uint32 kServerInitialFlowControlWindow = 100 * net::kMaxPacketSize;
namespace net {
namespace tools {
@@ -43,9 +45,6 @@ QuicServer::QuicServer()
supported_versions_(QuicSupportedVersions()) {
// Use hardcoded crypto parameters for now.
config_.SetDefaults();
- config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs, 0);
- config_.set_server_initial_congestion_window(kMaxInitialWindow,
- kDefaultInitialWindow);
Initialize();
}
@@ -76,6 +75,9 @@ void QuicServer::Initialize() {
crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
QuicCryptoServerConfig::ConfigOptions()));
+
+ // Set flow control options in the config.
+ config_.SetInitialCongestionWindowToSend(kServerInitialFlowControlWindow);
}
QuicServer::~QuicServer() {
@@ -107,6 +109,19 @@ bool QuicServer::Listen(const IPEndPoint& address) {
overflow_supported_ = true;
}
+ // These send and receive buffer sizes are sized for a single connection,
+ // because the default usage of QuicServer is as a test server with one or
+ // two clients. Adjust higher for use with many clients.
+ if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
+ if (!QuicSocketUtils::SetSendBufferSize(fd_,
+ TcpReceiver::kReceiveWindowTCP)) {
+ return false;
+ }
+
// Enable the socket option that allows the local address to be
// returned if the socket is bound to more than on address.
int get_local_ip = 1;
@@ -133,7 +148,7 @@ bool QuicServer::Listen(const IPEndPoint& address) {
return false;
}
- LOG(INFO) << "Listening on " << address.ToString();
+ DVLOG(1) << "Listening on " << address.ToString();
if (port_ == 0) {
SockaddrStorage storage;
IPEndPoint server_address;
@@ -143,17 +158,24 @@ bool QuicServer::Listen(const IPEndPoint& address) {
return false;
}
port_ = server_address.port();
- LOG(INFO) << "Kernel assigned port is " << port_;
+ DVLOG(1) << "Kernel assigned port is " << port_;
}
epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- dispatcher_.reset(new QuicDispatcher(config_, crypto_config_,
- supported_versions_,
- fd_, &epoll_server_));
+ dispatcher_.reset(CreateQuicDispatcher());
+ dispatcher_->Initialize(fd_);
return true;
}
+QuicDispatcher* QuicServer::CreateQuicDispatcher() {
+ return new QuicDispatcher(
+ config_,
+ crypto_config_,
+ supported_versions_,
+ &epoll_server_);
+}
+
void QuicServer::WaitForEvents() {
epoll_server_.WaitForEventsAndExecuteCallbacks();
}
@@ -172,7 +194,7 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
event->out_ready_mask = 0;
if (event->in_events & EPOLLIN) {
- LOG(ERROR) << "EPOLLIN";
+ DVLOG(1) << "EPOLLIN";
bool read = true;
while (read) {
read = ReadAndDispatchSinglePacket(
@@ -181,8 +203,8 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
}
}
if (event->in_events & EPOLLOUT) {
- bool can_write_more = dispatcher_->OnCanWrite();
- if (can_write_more) {
+ dispatcher_->OnCanWrite();
+ if (dispatcher_->HasPendingWrites()) {
event->out_ready_mask |= EPOLLOUT;
}
}
@@ -191,25 +213,10 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
}
/* static */
-void QuicServer::MaybeDispatchPacket(QuicDispatcher* dispatcher,
- const QuicEncryptedPacket& packet,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address) {
- QuicGuid guid;
- if (!QuicFramer::ReadGuidFromPacket(packet, &guid)) {
- return;
- }
-
- bool has_version_flag = QuicFramer::HasVersionFlag(packet);
-
- dispatcher->ProcessPacket(
- server_address, client_address, guid, has_version_flag, packet);
-}
-
bool QuicServer::ReadAndDispatchSinglePacket(int fd,
int port,
QuicDispatcher* dispatcher,
- int* packets_dropped) {
+ uint32* packets_dropped) {
// Allocate some extra space so we can send an error if the client goes over
// the limit.
char buf[2 * kMaxPacketSize];
@@ -228,7 +235,7 @@ bool QuicServer::ReadAndDispatchSinglePacket(int fd,
QuicEncryptedPacket packet(buf, bytes_read, false);
IPEndPoint server_address(server_ip, port);
- MaybeDispatchPacket(dispatcher, packet, server_address, client_address);
+ dispatcher->ProcessPacket(server_address, client_address, packet);
return true;
}
diff --git a/chromium/net/tools/quic/quic_server.h b/chromium/net/tools/quic/quic_server.h
index 7c8e4054f53..6285fd769d9 100644
--- a/chromium/net/tools/quic/quic_server.h
+++ b/chromium/net/tools/quic/quic_server.h
@@ -8,6 +8,7 @@
#ifndef NET_TOOLS_QUIC_QUIC_SERVER_H_
#define NET_TOOLS_QUIC_QUIC_SERVER_H_
+#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
@@ -44,8 +45,9 @@ class QuicServer : public EpollCallbackInterface {
void Shutdown();
// From EpollCallbackInterface
- virtual void OnRegistration(
- EpollServer* eps, int fd, int event_mask) OVERRIDE {}
+ virtual void OnRegistration(EpollServer* eps,
+ int fd,
+ int event_mask) OVERRIDE {}
virtual void OnModification(int fd, int event_mask) OVERRIDE {}
virtual void OnEvent(int fd, EpollEvent* event) OVERRIDE;
virtual void OnUnregistration(int fd, bool replaced) OVERRIDE {}
@@ -58,28 +60,38 @@ class QuicServer : public EpollCallbackInterface {
// dropped packets.
static bool ReadAndDispatchSinglePacket(int fd, int port,
QuicDispatcher* dispatcher,
- int* packets_dropped);
+ uint32* packets_dropped);
virtual void OnShutdown(EpollServer* eps, int fd) OVERRIDE {}
- // Dispatches the given packet only if it looks like a valid QUIC packet.
- // TODO(rjshade): Return a status describing why a packet was dropped, and log
- // somehow. Maybe expose as a varz.
- static void MaybeDispatchPacket(QuicDispatcher* dispatcher,
- const QuicEncryptedPacket& packet,
- const IPEndPoint& server_address,
- const IPEndPoint& client_address);
-
void SetStrikeRegisterNoStartupPeriod() {
crypto_config_.set_strike_register_no_startup_period();
}
+ // SetProofSource sets the ProofSource that will be used to verify the
+ // server's certificate, and takes ownership of |source|.
+ void SetProofSource(ProofSource* source) {
+ crypto_config_.SetProofSource(source);
+ }
+
bool overflow_supported() { return overflow_supported_; }
- int packets_dropped() { return packets_dropped_; }
+ uint32 packets_dropped() { return packets_dropped_; }
int port() { return port_; }
+ protected:
+ virtual QuicDispatcher* CreateQuicDispatcher();
+
+ const QuicConfig& config() const { return config_; }
+ const QuicCryptoServerConfig& crypto_config() const {
+ return crypto_config_;
+ }
+ const QuicVersionVector& supported_versions() const {
+ return supported_versions_;
+ }
+ EpollServer* epoll_server() { return &epoll_server_; }
+
private:
friend class net::tools::test::QuicServerPeer;
@@ -100,7 +112,7 @@ class QuicServer : public EpollCallbackInterface {
// If overflow_supported_ is true this will be the number of packets dropped
// during the lifetime of the server. This may overflow if enough packets
// are dropped.
- int packets_dropped_;
+ uint32 packets_dropped_;
// True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
// because the socket would otherwise overflow.
@@ -121,6 +133,10 @@ class QuicServer : public EpollCallbackInterface {
// skipped as necessary).
QuicVersionVector supported_versions_;
+ // Size of flow control receive window to advertise to clients on new
+ // connections.
+ uint32 server_initial_flow_control_receive_window_;
+
DISALLOW_COPY_AND_ASSIGN(QuicServer);
};
diff --git a/chromium/net/tools/quic/quic_server_bin.cc b/chromium/net/tools/quic/quic_server_bin.cc
index a71cbcf6218..2d349ac4792 100644
--- a/chromium/net/tools/quic/quic_server_bin.cc
+++ b/chromium/net/tools/quic/quic_server_bin.cc
@@ -10,6 +10,7 @@
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_endpoint.h"
#include "net/tools/quic/quic_in_memory_cache.h"
@@ -20,8 +21,13 @@
int32 FLAGS_port = 6121;
int main(int argc, char *argv[]) {
- CommandLine::Init(argc, argv);
- CommandLine* line = CommandLine::ForCurrentProcess();
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* line = base::CommandLine::ForCurrentProcess();
+
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ CHECK(logging::InitLogging(settings));
+
if (line->HasSwitch("h") || line->HasSwitch("help")) {
const char* help_str =
"Usage: quic_server [options]\n"
diff --git a/chromium/net/tools/quic/quic_server_session.cc b/chromium/net/tools/quic/quic_server_session.cc
index dcb112e0204..d7bc3b84e70 100644
--- a/chromium/net/tools/quic/quic_server_session.cc
+++ b/chromium/net/tools/quic/quic_server_session.cc
@@ -12,16 +12,13 @@
namespace net {
namespace tools {
-QuicServerSession::QuicServerSession(
- const QuicConfig& config,
- QuicConnection* connection,
- QuicSessionOwner* owner)
+QuicServerSession::QuicServerSession(const QuicConfig& config,
+ QuicConnection* connection,
+ QuicServerSessionVisitor* visitor)
: QuicSession(connection, config),
- owner_(owner) {
-}
+ visitor_(visitor) {}
-QuicServerSession::~QuicServerSession() {
-}
+QuicServerSession::~QuicServerSession() {}
void QuicServerSession::InitializeSession(
const QuicCryptoServerConfig& crypto_config) {
@@ -36,18 +33,28 @@ QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
bool from_peer) {
QuicSession::OnConnectionClosed(error, from_peer);
- owner_->OnConnectionClosed(connection()->guid(), error);
+ // In the unlikely event we get a connection close while doing an asynchronous
+ // crypto event, make sure we cancel the callback.
+ if (crypto_stream_.get() != NULL) {
+ crypto_stream_->CancelOutstandingCallbacks();
+ }
+ visitor_->OnConnectionClosed(connection()->connection_id(), error);
+}
+
+void QuicServerSession::OnWriteBlocked() {
+ QuicSession::OnWriteBlocked();
+ visitor_->OnWriteBlocked(connection());
}
bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
if (id % 2 == 0) {
- DLOG(INFO) << "Invalid incoming even stream_id:" << id;
+ DVLOG(1) << "Invalid incoming even stream_id:" << id;
connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
return false;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
- DLOG(INFO) << "Failed to create a new incoming stream with id:" << id
- << " Already " << GetNumOpenStreams() << " open.";
+ DVLOG(1) << "Failed to create a new incoming stream with id:" << id
+ << " Already " << GetNumOpenStreams() << " open.";
connection()->SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS);
return false;
}
diff --git a/chromium/net/tools/quic/quic_server_session.h b/chromium/net/tools/quic/quic_server_session.h
index f4705519791..e05ba161d4f 100644
--- a/chromium/net/tools/quic/quic_server_session.h
+++ b/chromium/net/tools/quic/quic_server_session.h
@@ -10,6 +10,7 @@
#include <set>
#include <vector>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/quic_crypto_server_stream.h"
@@ -18,6 +19,7 @@
namespace net {
+class QuicBlockedWriterInterface;
class QuicConfig;
class QuicConnection;
class QuicCryptoServerConfig;
@@ -31,28 +33,33 @@ class QuicServerSessionPeer;
// An interface from the session to the entity owning the session.
// This lets the session notify its owner (the Dispatcher) when the connection
-// is closed.
-class QuicSessionOwner {
+// is closed or blocked.
+class QuicServerSessionVisitor {
public:
- virtual ~QuicSessionOwner() {}
+ virtual ~QuicServerSessionVisitor() {}
- virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) = 0;
+ virtual void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error) = 0;
+ virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) = 0;
};
class QuicServerSession : public QuicSession {
public:
QuicServerSession(const QuicConfig& config,
- QuicConnection *connection,
- QuicSessionOwner* owner);
+ QuicConnection* connection,
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
+ virtual void OnWriteBlocked() OVERRIDE;
virtual ~QuicServerSession();
virtual void InitializeSession(const QuicCryptoServerConfig& crypto_config);
- const QuicCryptoServerStream* crypto_stream() { return crypto_stream_.get(); }
+ const QuicCryptoServerStream* crypto_stream() const {
+ return crypto_stream_.get();
+ }
protected:
// QuicSession methods:
@@ -66,13 +73,13 @@ class QuicServerSession : public QuicSession {
virtual bool ShouldCreateIncomingDataStream(QuicStreamId id);
virtual QuicCryptoServerStream* CreateQuicCryptoServerStream(
- const QuicCryptoServerConfig& crypto_config);
+ const QuicCryptoServerConfig& crypto_config);
private:
friend class test::QuicServerSessionPeer;
scoped_ptr<QuicCryptoServerStream> crypto_stream_;
- QuicSessionOwner* owner_;
+ QuicServerSessionVisitor* visitor_;
DISALLOW_COPY_AND_ASSIGN(QuicServerSession);
};
diff --git a/chromium/net/tools/quic/quic_server_session_test.cc b/chromium/net/tools/quic/quic_server_session_test.cc
index a3dd9968285..1e04a7fd768 100644
--- a/chromium/net/tools/quic/quic_server_session_test.cc
+++ b/chromium/net/tools/quic/quic_server_session_test.cc
@@ -7,10 +7,10 @@
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_data_stream_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_spdy_server_stream.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -20,8 +20,13 @@ using __gnu_cxx::vector;
using net::test::MockConnection;
using net::test::QuicConnectionPeer;
using net::test::QuicDataStreamPeer;
-using testing::_;
+using net::test::SupportedVersions;
+using net::test::kClientDataStreamId1;
+using net::test::kClientDataStreamId2;
+using net::test::kClientDataStreamId3;
+using net::test::kClientDataStreamId4;
using testing::StrictMock;
+using testing::_;
namespace net {
namespace tools {
@@ -29,206 +34,152 @@ namespace test {
class QuicServerSessionPeer {
public:
- static QuicDataStream* GetIncomingReliableStream(
+ static QuicDataStream* GetIncomingDataStream(
QuicServerSession* s, QuicStreamId id) {
- return s->GetIncomingReliableStream(id);
+ return s->GetIncomingDataStream(id);
}
static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) {
return s->GetDataStream(id);
}
};
-class CloseOnDataStream : public QuicDataStream {
- public:
- CloseOnDataStream(QuicStreamId id, QuicSession* session)
- : QuicDataStream(id, session) {
- }
-
- virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
- session()->MarkDecompressionBlocked(1, id());
- session()->CloseStream(id());
- return true;
- }
-
- virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE {
- return 0;
- }
-};
-
-class TestQuicQuicServerSession : public QuicServerSession {
- public:
- TestQuicQuicServerSession(const QuicConfig& config,
- QuicConnection* connection,
- QuicSessionOwner* owner)
- : QuicServerSession(config, connection, owner),
- close_stream_on_data_(false) {
- }
-
- virtual QuicDataStream* CreateIncomingDataStream(
- QuicStreamId id) OVERRIDE {
- if (!ShouldCreateIncomingDataStream(id)) {
- return NULL;
- }
- if (close_stream_on_data_) {
- return new CloseOnDataStream(id, this);
- } else {
- return new QuicSpdyServerStream(id, this);
- }
- }
-
- void CloseStreamOnData() {
- close_stream_on_data_ = true;
- }
-
- private:
- bool close_stream_on_data_;
-};
-
namespace {
-class QuicServerSessionTest : public ::testing::Test {
+class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicServerSessionTest()
: crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance()) {
config_.SetDefaults();
config_.set_max_streams_per_connection(3, 3);
-
- connection_ = new MockConnection(true);
- session_.reset(new TestQuicQuicServerSession(
- config_, connection_, &owner_));
+ config_.SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ config_.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ config_.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+
+ connection_ =
+ new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
+ session_.reset(new QuicServerSession(config_, connection_, &owner_));
session_->InitializeSession(crypto_config_);
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
}
- void MarkHeadersReadForStream(QuicStreamId id) {
- QuicDataStream* stream = QuicServerSessionPeer::GetDataStream(
- session_.get(), id);
- ASSERT_TRUE(stream != NULL);
- QuicDataStreamPeer::SetHeadersDecompressed(stream, true);
- }
+ QuicVersion version() const { return connection_->version(); }
- StrictMock<MockQuicSessionOwner> owner_;
- MockConnection* connection_;
+ StrictMock<MockQuicServerSessionVisitor> owner_;
+ StrictMock<MockConnection>* connection_;
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
- scoped_ptr<TestQuicQuicServerSession> session_;
+ scoped_ptr<QuicServerSession> session_;
QuicConnectionVisitorInterface* visitor_;
};
-TEST_F(QuicServerSessionTest, CloseStreamDueToReset) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicServerSessionTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicServerSessionTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
// Send two bytes of payload to open it.
- QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ session_->OnStreamFrames(frames);
EXPECT_EQ(1u, session_->GetNumOpenStreams());
- // Pretend we got full headers, so we won't trigger the 'unrecoverable
- // compression context' state.
- MarkHeadersReadForStream(3);
-
- // Send a reset.
- QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst1);
EXPECT_EQ(0u, session_->GetNumOpenStreams());
// Send the same two bytes of payload in a new packet.
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ visitor_->OnStreamFrames(frames);
// The stream should not be re-opened.
EXPECT_EQ(0u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, NeverOpenStreamDueToReset) {
- // Send a reset.
- QuicRstStreamFrame rst1(3, QUIC_STREAM_NO_ERROR);
+TEST_P(QuicServerSessionTest, NeverOpenStreamDueToReset) {
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst1);
EXPECT_EQ(0u, session_->GetNumOpenStreams());
// Send two bytes of payload.
- QuicStreamFrame data1(3, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
-
- // When we get data for the closed stream, it implies the far side has
- // compressed some headers. As a result we're going to bail due to
- // unrecoverable compression context state.
- EXPECT_CALL(*connection_, SendConnectionClose(
- QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
- EXPECT_FALSE(visitor_->OnStreamFrames(frames));
+ visitor_->OnStreamFrames(frames);
// The stream should never be opened, now that the reset is received.
EXPECT_EQ(0u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, GoOverPrematureClosedStreamLimit) {
- QuicStreamFrame data1(3, false, 0, MakeIOVector("H"));
- vector<QuicStreamFrame> frames;
- frames.push_back(data1);
-
- // Set up the stream such that it's open in OnPacket, but closes half way
- // through while on the decompression blocked list.
- session_->CloseStreamOnData();
-
- EXPECT_CALL(*connection_, SendConnectionClose(
- QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED));
- EXPECT_FALSE(visitor_->OnStreamFrames(frames));
-}
-
-TEST_F(QuicServerSessionTest, AcceptClosedStream) {
+TEST_P(QuicServerSessionTest, AcceptClosedStream) {
vector<QuicStreamFrame> frames;
// Send (empty) compressed headers followed by two bytes of data.
- frames.push_back(
- QuicStreamFrame(3, false, 0, MakeIOVector("\1\0\0\0\0\0\0\0HT")));
- frames.push_back(
- QuicStreamFrame(5, false, 0, MakeIOVector("\2\0\0\0\0\0\0\0HT")));
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
-
- // Pretend we got full headers, so we won't trigger the 'unercoverable
- // compression context' state.
- MarkHeadersReadForStream(3);
-
- // Send a reset.
- QuicRstStreamFrame rst(3, QUIC_STREAM_NO_ERROR);
+ frames.push_back(QuicStreamFrame(kClientDataStreamId1, false, 0,
+ MakeIOVector("\1\0\0\0\0\0\0\0HT")));
+ frames.push_back(QuicStreamFrame(kClientDataStreamId2, false, 0,
+ MakeIOVector("\2\0\0\0\0\0\0\0HT")));
+ visitor_->OnStreamFrames(frames);
+ EXPECT_EQ(2u, session_->GetNumOpenStreams());
+
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0);
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1,
+ QUIC_RST_FLOW_CONTROL_ACCOUNTING, 0));
visitor_->OnRstStream(rst);
// If we were tracking, we'd probably want to reject this because it's data
// past the reset point of stream 3. As it's a closed stream we just drop the
// data on the floor, but accept the packet because it has data for stream 5.
frames.clear();
- frames.push_back(QuicStreamFrame(3, false, 2, MakeIOVector("TP")));
- frames.push_back(QuicStreamFrame(5, false, 2, MakeIOVector("TP")));
- EXPECT_TRUE(visitor_->OnStreamFrames(frames));
+ frames.push_back(
+ QuicStreamFrame(kClientDataStreamId1, false, 2, MakeIOVector("TP")));
+ frames.push_back(
+ QuicStreamFrame(kClientDataStreamId2, false, 2, MakeIOVector("TP")));
+ visitor_->OnStreamFrames(frames);
+ // The stream should never be opened, now that the reset is received.
+ EXPECT_EQ(1u, session_->GetNumOpenStreams());
+ EXPECT_TRUE(connection_->connected());
}
-TEST_F(QuicServerSessionTest, MaxNumConnections) {
+TEST_P(QuicServerSessionTest, MaxNumConnections) {
EXPECT_EQ(0u, session_->GetNumOpenStreams());
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 5));
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 7));
- EXPECT_FALSE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId1));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId2));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId3));
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
+ EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId4));
}
-TEST_F(QuicServerSessionTest, MaxNumConnectionsImplicit) {
+TEST_P(QuicServerSessionTest, MaxNumConnectionsImplicit) {
EXPECT_EQ(0u, session_->GetNumOpenStreams());
- EXPECT_TRUE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 3));
- // Implicitly opens two more streams before 9.
- EXPECT_FALSE(
- QuicServerSessionPeer::GetIncomingReliableStream(session_.get(), 9));
+ EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId1));
+ // Implicitly opens two more streams.
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS));
+ EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDataStream(
+ session_.get(), kClientDataStreamId4));
}
-TEST_F(QuicServerSessionTest, GetEvenIncomingError) {
+TEST_P(QuicServerSessionTest, GetEvenIncomingError) {
// Incoming streams on the server session must be odd.
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
EXPECT_EQ(NULL,
- QuicServerSessionPeer::GetIncomingReliableStream(
- session_.get(), 2));
+ QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4));
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_server_test.cc b/chromium/net/tools/quic/quic_server_test.cc
index 7d24edc28bb..e2d7c4f3288 100644
--- a/chromium/net/tools/quic/quic_server_test.cc
+++ b/chromium/net/tools/quic/quic_server_test.cc
@@ -21,13 +21,13 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
public:
QuicServerDispatchPacketTest()
: crypto_config_("blah", QuicRandom::GetInstance()),
- dispatcher_(config_, crypto_config_, 1234, &eps_) {}
-
+ dispatcher_(config_, crypto_config_, &eps_) {
+ dispatcher_.Initialize(1234);
+ }
- void MaybeDispatchPacket(const QuicEncryptedPacket& packet) {
+ void DispatchPacket(const QuicEncryptedPacket& packet) {
IPEndPoint client_addr, server_addr;
- QuicServer::MaybeDispatchPacket(&dispatcher_, packet,
- client_addr, server_addr);
+ dispatcher_.ProcessPacket(server_addr, client_addr, packet);
}
protected:
@@ -37,23 +37,11 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
MockQuicDispatcher dispatcher_;
};
-TEST_F(QuicServerDispatchPacketTest, DoNotDispatchPacketWithoutGUID) {
- // Packet too short to be considered valid.
- unsigned char invalid_packet[] = { 0x00 };
- QuicEncryptedPacket encrypted_invalid_packet(
- QuicUtils::AsChars(invalid_packet), arraysize(invalid_packet), false);
-
- // We expect the invalid packet to be dropped, and ProcessPacket should never
- // be called.
- EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _, _)).Times(0);
- MaybeDispatchPacket(encrypted_invalid_packet);
-}
-
-TEST_F(QuicServerDispatchPacketTest, DispatchValidPacket) {
+TEST_F(QuicServerDispatchPacketTest, DispatchPacket) {
unsigned char valid_packet[] = {
- // public flags (8 byte guid)
+ // public flags (8 byte connection_id)
0x3C,
- // guid
+ // connection_id
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// packet sequence number
@@ -64,8 +52,8 @@ TEST_F(QuicServerDispatchPacketTest, DispatchValidPacket) {
QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
arraysize(valid_packet), false);
- EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _, _)).Times(1);
- MaybeDispatchPacket(encrypted_valid_packet);
+ EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1);
+ DispatchPacket(encrypted_valid_packet);
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_socket_utils.cc b/chromium/net/tools/quic/quic_socket_utils.cc
index 87071a681ae..3202150917b 100644
--- a/chromium/net/tools/quic/quic_socket_utils.cc
+++ b/chromium/net/tools/quic/quic_socket_utils.cc
@@ -11,6 +11,7 @@
#include <sys/uio.h>
#include <string>
+#include "base/basictypes.h"
#include "base/logging.h"
#include "net/quic/quic_protocol.h"
@@ -51,7 +52,7 @@ IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) {
// static
bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr *hdr,
- int *dropped_packets) {
+ uint32 *dropped_packets) {
if (hdr->msg_controllen > 0) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(hdr);
@@ -79,8 +80,26 @@ int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
}
// static
+bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) {
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
+ LOG(ERROR) << "Failed to set socket send size";
+ return false;
+ }
+ return true;
+}
+
+// static
+bool QuicSocketUtils::SetReceiveBufferSize(int fd, size_t size) {
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
+ LOG(ERROR) << "Failed to set socket recv size";
+ return false;
+ }
+ return true;
+}
+
+// static
int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
- int* dropped_packets,
+ uint32* dropped_packets,
IPAddressNumber* self_address,
IPEndPoint* peer_address) {
CHECK(peer_address != NULL);
@@ -135,6 +154,28 @@ int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len,
return bytes_read;
}
+size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddressNumber& self_address,
+ cmsghdr* cmsg) {
+ if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in_pktinfo));
+ pktinfo->ipi_ifindex = 0;
+ memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
+ return sizeof(in_pktinfo);
+ } else {
+ cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
+ memset(pktinfo, 0, sizeof(in6_pktinfo));
+ memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
+ return sizeof(in6_pktinfo);
+ }
+}
+
// static
WriteResult QuicSocketUtils::WritePacket(int fd,
const char* buffer,
@@ -164,30 +205,11 @@ WriteResult QuicSocketUtils::WritePacket(int fd,
if (self_address.empty()) {
hdr.msg_control = 0;
hdr.msg_controllen = 0;
- } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
- hdr.msg_control = cbuf;
- hdr.msg_controllen = kSpaceForIp;
- cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
-
- cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
- memset(pktinfo, 0, sizeof(in_pktinfo));
- pktinfo->ipi_ifindex = 0;
- memcpy(&pktinfo->ipi_spec_dst, &self_address[0], self_address.size());
- hdr.msg_controllen = cmsg->cmsg_len;
} else {
hdr.msg_control = cbuf;
hdr.msg_controllen = kSpaceForIp;
- cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
-
- cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
- cmsg->cmsg_level = IPPROTO_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
- memset(pktinfo, 0, sizeof(in6_pktinfo));
- memcpy(&pktinfo->ipi6_addr, &self_address[0], self_address.size());
+ cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+ SetIpInfoInCmsg(self_address, cmsg);
hdr.msg_controllen = cmsg->cmsg_len;
}
diff --git a/chromium/net/tools/quic/quic_socket_utils.h b/chromium/net/tools/quic/quic_socket_utils.h
index 8f0feffced2..03b95e5179e 100644
--- a/chromium/net/tools/quic/quic_socket_utils.h
+++ b/chromium/net/tools/quic/quic_socket_utils.h
@@ -11,8 +11,9 @@
#include <sys/socket.h>
#include <string>
+#include "base/basictypes.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_types.h"
namespace net {
namespace tools {
@@ -26,12 +27,19 @@ class QuicSocketUtils {
// If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
// to the correct value and return true. Otherwise it will return false.
- static bool GetOverflowFromMsghdr(struct msghdr *hdr, int *dropped_packets);
+ static bool GetOverflowFromMsghdr(struct msghdr *hdr,
+ uint32 *dropped_packets);
// Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on
// address_family. Returns the return code from setsockopt.
static int SetGetAddressInfo(int fd, int address_family);
+ // Sets the send buffer size to |size| and returns false if it fails.
+ static bool SetSendBufferSize(int fd, size_t size);
+
+ // Sets the receive buffer size to |size| and returns false if it fails.
+ static bool SetReceiveBufferSize(int fd, size_t size);
+
// Reads buf_len from the socket. If reading is successful, returns bytes
// read and sets peer_address to the peer address. Otherwise returns -1.
//
@@ -41,8 +49,10 @@ class QuicSocketUtils {
//
// If self_address is non-null, it will be set to the address the peer sent
// packets to, assuming a packet was read.
- static int ReadPacket(int fd, char* buffer, size_t buf_len,
- int* dropped_packets,
+ static int ReadPacket(int fd,
+ char* buffer,
+ size_t buf_len,
+ uint32* dropped_packets,
IPAddressNumber* self_address,
IPEndPoint* peer_address);
@@ -50,9 +60,20 @@ class QuicSocketUtils {
// status to WRITE_STATUS_OK and sets bytes_written. Otherwise sets the
// result's status to WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and sets
// error_code to errno.
- static WriteResult WritePacket(int fd, const char* buffer, size_t buf_len,
+ static WriteResult WritePacket(int fd,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& self_address,
const IPEndPoint& peer_address);
+
+ // A helper for WritePacket which fills in the cmsg with the supplied self
+ // address.
+ // Returns the length of the packet info structure used.
+ static size_t SetIpInfoInCmsg(const IPAddressNumber& self_address,
+ cmsghdr* cmsg);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicSocketUtils);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.cc b/chromium/net/tools/quic/quic_spdy_client_stream.cc
index 1956c7940db..8423295a1ac 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.cc
@@ -20,7 +20,9 @@ QuicSpdyClientStream::QuicSpdyClientStream(QuicStreamId id,
QuicClientSession* session)
: QuicDataStream(id, session),
read_buf_(new GrowableIOBuffer()),
- response_headers_received_(false) {
+ response_headers_received_(false),
+ header_bytes_read_(0),
+ header_bytes_written_(0) {
}
QuicSpdyClientStream::~QuicSpdyClientStream() {
@@ -28,29 +30,37 @@ QuicSpdyClientStream::~QuicSpdyClientStream() {
bool QuicSpdyClientStream::OnStreamFrame(const QuicStreamFrame& frame) {
if (!write_side_closed()) {
- DLOG(INFO) << "Got a response before the request was complete. "
- << "Aborting request.";
+ DVLOG(1) << "Got a response before the request was complete. "
+ << "Aborting request.";
CloseWriteSide();
}
return QuicDataStream::OnStreamFrame(frame);
}
-uint32 QuicSpdyClientStream::ProcessData(const char* data, uint32 length) {
- uint32 total_bytes_processed = 0;
+void QuicSpdyClientStream::OnStreamHeadersComplete(bool fin,
+ size_t frame_len) {
+ header_bytes_read_ = frame_len;
+ QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
+}
+
+uint32 QuicSpdyClientStream::ProcessData(const char* data,
+ uint32 data_len) {
+ int total_bytes_processed = 0;
// Are we still reading the response headers.
if (!response_headers_received_) {
// Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() < (int)length) {
+ if (read_buf_->RemainingCapacity() < (int)data_len) {
read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
}
- memcpy(read_buf_->data(), data, length);
- read_buf_->set_offset(read_buf_->offset() + length);
+ memcpy(read_buf_->data(), data, data_len);
+ read_buf_->set_offset(read_buf_->offset() + data_len);
ParseResponseHeaders();
} else {
- data_.append(data + total_bytes_processed, length - total_bytes_processed);
+ data_.append(data + total_bytes_processed,
+ data_len - total_bytes_processed);
}
- return length;
+ return data_len;
}
void QuicSpdyClientStream::OnFinRead() {
@@ -71,15 +81,16 @@ ssize_t QuicSpdyClientStream::SendRequest(const BalsaHeaders& headers,
SpdyUtils::RequestHeadersToSpdyHeaders(headers);
bool send_fin_with_headers = fin && body.empty();
- string headers_string = session()->compressor()->CompressHeadersWithPriority(
- priority(), header_block);
- WriteOrBufferData(headers_string, send_fin_with_headers);
+ size_t bytes_sent = body.size();
+ header_bytes_written_ = WriteHeaders(
+ header_block, send_fin_with_headers, NULL);
+ bytes_sent += header_bytes_written_;
if (!body.empty()) {
- WriteOrBufferData(body, fin);
+ WriteOrBufferData(body, fin, NULL);
}
- return headers_string.size() + body.size();
+ return bytes_sent;
}
int QuicSpdyClientStream::ParseResponseHeaders() {
@@ -109,7 +120,7 @@ int QuicSpdyClientStream::ParseResponseHeaders() {
// Sends body data to the server and returns the number of bytes sent.
void QuicSpdyClientStream::SendBody(const string& data, bool fin) {
- return WriteOrBufferData(data, fin);
+ WriteOrBufferData(data, fin, NULL);
}
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.h b/chromium/net/tools/quic/quic_spdy_client_stream.h
index 2b17205f53e..1292e197603 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.h
@@ -8,6 +8,7 @@
#include <sys/types.h>
#include <string>
+#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "net/base/io_buffer.h"
#include "net/quic/quic_data_stream.h"
@@ -33,6 +34,9 @@ class QuicSpdyClientStream : public QuicDataStream {
// SPDY/HTTP does not support bidirectional streaming.
virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE;
+ // Override the base class to store the size of the headers.
+ virtual void OnStreamHeadersComplete(bool fin, size_t frame_len) OVERRIDE;
+
// ReliableQuicStream implementation called by the session when there's
// data for us.
virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE;
@@ -54,6 +58,10 @@ class QuicSpdyClientStream : public QuicDataStream {
// Returns whatever headers have been received for this stream.
const BalsaHeaders& headers() { return headers_; }
+ size_t header_bytes_read() const { return header_bytes_read_; }
+
+ size_t header_bytes_written() const { return header_bytes_written_; }
+
// While the server's set_priority shouldn't be called externally, the creator
// of client-side streams should be able to set the priority.
using QuicDataStream::set_priority;
@@ -66,6 +74,10 @@ class QuicSpdyClientStream : public QuicDataStream {
scoped_refptr<GrowableIOBuffer> read_buf_;
bool response_headers_received_;
+ size_t header_bytes_read_;
+ size_t header_bytes_written_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyClientStream);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
index 44c640cbdea..475f832b1c5 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -7,7 +7,6 @@
#include "base/strings/string_number_conversions.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
#include "net/tools/quic/spdy_utils.h"
@@ -16,6 +15,8 @@
#include "testing/gtest/include/gtest/gtest.h"
using net::test::DefaultQuicConfig;
+using net::test::SupportedVersions;
+using testing::StrictMock;
using testing::TestWithParam;
namespace net {
@@ -23,23 +24,35 @@ namespace tools {
namespace test {
namespace {
-class QuicSpdyClientStreamTest : public ::testing::Test {
+class QuicSpdyClientStreamTest : public TestWithParam<QuicVersion> {
public:
QuicSpdyClientStreamTest()
- : session_("example.com", DefaultQuicConfig(),
- new MockConnection(false),
+ : connection_(new StrictMock<MockConnection>(
+ false, SupportedVersions(GetParam()))),
+ session_(QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
+ DefaultQuicConfig(),
+ connection_,
&crypto_config_),
body_("hello world") {
- session_.config()->SetDefaults();
crypto_config_.SetDefaults();
headers_.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "Ok");
headers_.ReplaceOrAppendHeader("content-length", "11");
headers_string_ = SpdyUtils::SerializeResponseHeaders(headers_);
+
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ session_.config()->SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ session_.config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session_.config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
stream_.reset(new QuicSpdyClientStream(3, &session_));
}
+ StrictMock<MockConnection>* connection_;
QuicClientSession session_;
scoped_ptr<QuicSpdyClientStream> stream_;
BalsaHeaders headers_;
@@ -48,7 +61,10 @@ class QuicSpdyClientStreamTest : public ::testing::Test {
QuicCryptoClientConfig crypto_config_;
};
-TEST_F(QuicSpdyClientStreamTest, TestFraming) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyClientStreamTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSpdyClientStreamTest, TestFraming) {
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
EXPECT_EQ(body_.size(),
@@ -57,7 +73,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFraming) {
EXPECT_EQ(body_, stream_->data());
}
-TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) {
+TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) {
string message = headers_string_ + body_;
EXPECT_EQ(message.size(), stream_->ProcessData(
@@ -66,7 +82,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) {
EXPECT_EQ(body_, stream_->data());
}
-TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
+TEST_P(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
string large_body = "hello world!!!!!!";
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
@@ -75,12 +91,14 @@ TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
EXPECT_EQ(200u, stream_->headers().parsed_response_code());
+ EXPECT_CALL(*connection_,
+ SendRstStream(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD, 0));
stream_->ProcessData(large_body.c_str(), large_body.size());
EXPECT_NE(QUIC_STREAM_NO_ERROR, stream_->stream_error());
}
-TEST_F(QuicSpdyClientStreamTest, TestNoBidirectionalStreaming) {
+TEST_P(QuicSpdyClientStreamTest, TestNoBidirectionalStreaming) {
QuicStreamFrame frame(3, false, 3, MakeIOVector("asd"));
EXPECT_FALSE(stream_->write_side_closed());
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream.cc b/chromium/net/tools/quic/quic_spdy_server_stream.cc
index c1a9cf15e18..7ae20d02e97 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_server_stream.cc
@@ -28,22 +28,23 @@ QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
QuicSpdyServerStream::~QuicSpdyServerStream() {
}
-uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 length) {
+uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
uint32 total_bytes_processed = 0;
// Are we still reading the request headers.
if (!request_headers_received_) {
// Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() < (int)length) {
+ if (read_buf_->RemainingCapacity() < (int)data_len) {
read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
}
- memcpy(read_buf_->data(), data, length);
- read_buf_->set_offset(read_buf_->offset() + length);
+ memcpy(read_buf_->data(), data, data_len);
+ read_buf_->set_offset(read_buf_->offset() + data_len);
ParseRequestHeaders();
} else {
- body_.append(data + total_bytes_processed, length - total_bytes_processed);
+ body_.append(data + total_bytes_processed,
+ data_len - total_bytes_processed);
}
- return length;
+ return data_len;
}
void QuicSpdyServerStream::OnFinRead() {
@@ -55,7 +56,7 @@ void QuicSpdyServerStream::OnFinRead() {
if (!request_headers_received_) {
SendErrorResponse(); // We're not done reading headers.
} else if ((headers_.content_length_status() ==
- BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
+ BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
body_.size() != headers_.content_length()) {
SendErrorResponse(); // Invalid content length
} else {
@@ -97,12 +98,23 @@ void QuicSpdyServerStream::SendResponse() {
return;
}
- DLOG(INFO) << "Sending response for stream " << id();
+ if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
+ DVLOG(1) << "Special response: closing connection.";
+ CloseConnection(QUIC_NO_ERROR);
+ return;
+ }
+
+ if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
+ DVLOG(1) << "Special response: ignoring request.";
+ return;
+ }
+
+ DVLOG(1) << "Sending response for stream " << id();
SendHeadersAndBody(response->headers(), response->body());
}
void QuicSpdyServerStream::SendErrorResponse() {
- DLOG(INFO) << "Sending error response for stream " << id();
+ DVLOG(1) << "Sending error response for stream " << id();
BalsaHeaders headers;
headers.SetResponseFirstlineFromStringPieces(
"HTTP/1.1", "500", "Server Error");
@@ -110,7 +122,7 @@ void QuicSpdyServerStream::SendErrorResponse() {
SendHeadersAndBody(headers, "bad");
}
-void QuicSpdyServerStream:: SendHeadersAndBody(
+void QuicSpdyServerStream::SendHeadersAndBody(
const BalsaHeaders& response_headers,
StringPiece body) {
// We only support SPDY and HTTP, and neither handles bidirectional streaming.
@@ -121,12 +133,10 @@ void QuicSpdyServerStream:: SendHeadersAndBody(
SpdyHeaderBlock header_block =
SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
- string headers_string =
- session()->compressor()->CompressHeaders(header_block);
- WriteOrBufferData(headers_string, body.empty());
+ WriteHeaders(header_block, body.empty(), NULL);
if (!body.empty()) {
- WriteOrBufferData(body, true);
+ WriteOrBufferData(body, true, NULL);
}
}
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream.h b/chromium/net/tools/quic/quic_spdy_server_stream.h
index 574ef76f33d..741f7867331 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_server_stream.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/basictypes.h"
#include "net/base/io_buffer.h"
#include "net/quic/quic_data_stream.h"
#include "net/quic/quic_protocol.h"
@@ -56,6 +57,8 @@ class QuicSpdyServerStream : public QuicDataStream {
// Buffer into which response header data is read.
scoped_refptr<GrowableIOBuffer> read_buf_;
bool request_headers_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyServerStream);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_spdy_server_stream_test.cc b/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
index c0ec9449707..e01569ede79 100644
--- a/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -8,7 +8,6 @@
#include "base/strings/string_piece.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_compressor.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
@@ -20,8 +19,9 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
-using net::tools::test::MockConnection;
using net::test::MockSession;
+using net::test::SupportedVersions;
+using net::tools::test::MockConnection;
using std::string;
using testing::_;
using testing::AnyNumber;
@@ -29,7 +29,6 @@ using testing::Invoke;
using testing::InvokeArgument;
using testing::InSequence;
using testing::Return;
-using testing::StrEq;
using testing::StrictMock;
using testing::WithArgs;
@@ -46,25 +45,35 @@ class QuicSpdyServerStreamPeer : public QuicSpdyServerStream {
using QuicSpdyServerStream::SendResponse;
using QuicSpdyServerStream::SendErrorResponse;
- const string& body() {
- return body_;
+ BalsaHeaders* mutable_headers() {
+ return &headers_;
}
- const BalsaHeaders& headers() {
- return headers_;
+ static void SendResponse(QuicSpdyServerStream* stream) {
+ stream->SendResponse();
}
- BalsaHeaders* mutable_headers() {
- return &headers_;
+ static void SendErrorResponse(QuicSpdyServerStream* stream) {
+ stream->SendResponse();
+ }
+
+ static const string& body(QuicSpdyServerStream* stream) {
+ return stream->body_;
+ }
+
+ static const BalsaHeaders& headers(QuicSpdyServerStream* stream) {
+ return stream->headers_;
}
};
namespace {
-class QuicSpdyServerStreamTest : public ::testing::Test {
+class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> {
public:
QuicSpdyServerStreamTest()
- : session_(new MockConnection(true)),
+ : connection_(new StrictMock<MockConnection>(
+ true, SupportedVersions(GetParam()))),
+ session_(connection_),
body_("hello world") {
BalsaHeaders request_headers;
request_headers.SetRequestFirstlineFromStringPieces(
@@ -72,35 +81,23 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
request_headers.ReplaceOrAppendHeader("content-length", "11");
headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers);
- stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
- }
- QuicConsumedData ValidateHeaders(const struct iovec* iov) {
- StringPiece headers =
- StringPiece(static_cast<const char*>(iov[0].iov_base), iov[0].iov_len);
- headers_string_ = SpdyUtils::SerializeResponseHeaders(
- response_headers_);
- QuicSpdyDecompressor decompressor;
- TestDecompressorVisitor visitor;
-
- // First the header id, then the compressed data.
- EXPECT_EQ(1, headers[0]);
- EXPECT_EQ(0, headers[1]);
- EXPECT_EQ(0, headers[2]);
- EXPECT_EQ(0, headers[3]);
- EXPECT_EQ(static_cast<size_t>(headers.length() - 4),
- decompressor.DecompressData(headers.substr(4), &visitor));
-
- EXPECT_EQ(headers_string_, visitor.data());
-
- return QuicConsumedData(headers.size(), false);
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ session_.config()->SetInitialFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ session_.config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session_.config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
}
static void SetUpTestCase() {
QuicInMemoryCachePeer::ResetForTests();
}
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
BalsaHeaders request_headers, response_headers;
@@ -130,8 +127,17 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
cache->AddResponse(request_headers, response_headers, body);
}
+ const string& StreamBody() {
+ return QuicSpdyServerStreamPeer::body(stream_.get());
+ }
+
+ const BalsaHeaders& StreamHeaders() {
+ return QuicSpdyServerStreamPeer::headers(stream_.get());
+ }
+
BalsaHeaders response_headers_;
EpollServer eps_;
+ StrictMock<MockConnection>* connection_;
StrictMock<MockSession> session_;
scoped_ptr<QuicSpdyServerStreamPeer> stream_;
string headers_string_;
@@ -140,32 +146,31 @@ class QuicSpdyServerStreamTest : public ::testing::Test {
QuicConsumedData ConsumeAllData(
QuicStreamId id,
- const struct iovec* iov,
- int iov_count,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
+ FecProtection /*fec_protection_*/,
QuicAckNotifier::DelegateInterface* /*ack_notifier_delegate*/) {
- ssize_t consumed_length = 0;
- for (int i = 0; i < iov_count; ++i) {
- consumed_length += iov[i].iov_len;
- }
- return QuicConsumedData(consumed_length, fin);
+ return QuicConsumedData(data.TotalBufferSize(), fin);
}
-TEST_F(QuicSpdyServerStreamTest, TestFraming) {
+INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyServerStreamTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicSpdyServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
EXPECT_EQ(headers_string_.size(), stream_->ProcessData(
headers_string_.c_str(), headers_string_.size()));
EXPECT_EQ(body_.size(), stream_->ProcessData(body_.c_str(), body_.size()));
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
- EXPECT_EQ(body_, stream_->body());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
+ EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingOnePacket) {
+TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()).
WillRepeatedly(Invoke(ConsumeAllData));
@@ -173,14 +178,13 @@ TEST_F(QuicSpdyServerStreamTest, TestFramingOnePacket) {
EXPECT_EQ(message.size(), stream_->ProcessData(
message.c_str(), message.size()));
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/",
- stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
- EXPECT_EQ(body_, stream_->body());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
+ EXPECT_EQ(body_, StreamBody());
}
-TEST_F(QuicSpdyServerStreamTest, TestFramingExtraData) {
+TEST_P(QuicSpdyServerStreamTest, TestFramingExtraData) {
string large_body = "hello world!!!!!!";
// We'll automatically write out an error (headers + body)
@@ -192,12 +196,12 @@ TEST_F(QuicSpdyServerStreamTest, TestFramingExtraData) {
// Content length is still 11. This will register as an error and we won't
// accept the bytes.
stream_->ProcessData(large_body.c_str(), large_body.size());
- EXPECT_EQ(11u, stream_->headers().content_length());
- EXPECT_EQ("https://www.google.com/", stream_->headers().request_uri());
- EXPECT_EQ("POST", stream_->headers().request_method());
+ EXPECT_EQ(11u, StreamHeaders().content_length());
+ EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri());
+ EXPECT_EQ("POST", StreamHeaders().request_method());
}
-TEST_F(QuicSpdyServerStreamTest, TestSendResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendResponse) {
BalsaHeaders* request_headers = stream_->mutable_headers();
request_headers->SetRequestFirstlineFromStringPieces(
"GET",
@@ -209,40 +213,34 @@ TEST_F(QuicSpdyServerStreamTest, TestSendResponse) {
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1)
- .WillOnce(WithArgs<1>(Invoke(
- this, &QuicSpdyServerStreamTest::ValidateHeaders)));
-
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1).
+ EXPECT_CALL(session_,
+ WritevData(kHeadersStreamId, _, 0, false, _, NULL));
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
- stream_->SendResponse();
+ QuicSpdyServerStreamPeer::SendResponse(stream_.get());
EXPECT_TRUE(stream_->read_side_closed());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, TestSendErrorResponse) {
+TEST_P(QuicSpdyServerStreamTest, TestSendErrorResponse) {
response_headers_.SetResponseFirstlineFromStringPieces(
"HTTP/1.1", "500", "Server Error");
response_headers_.ReplaceOrAppendHeader("content-length", "3");
InSequence s;
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1)
- .WillOnce(WithArgs<1>(Invoke(
- this, &QuicSpdyServerStreamTest::ValidateHeaders)));
-
- EXPECT_CALL(session_, WritevData(_, _, 1, _, _, _)).Times(1).
+ EXPECT_CALL(session_,
+ WritevData(kHeadersStreamId, _, 0, false, _, NULL));
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1).
WillOnce(Return(QuicConsumedData(3, true)));
- stream_->SendErrorResponse();
+ QuicSpdyServerStreamPeer::SendErrorResponse(stream_.get());
EXPECT_TRUE(stream_->read_side_closed());
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_F(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
+TEST_P(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
char arr[] = {
- 0x00, 0x00, 0x00, 0x05, // ....
- 0x00, 0x00, 0x00, 0x05, // ....
0x3a, 0x68, 0x6f, 0x73, // :hos
0x74, 0x00, 0x00, 0x00, // t...
0x00, 0x00, 0x00, 0x00, // ....
@@ -265,8 +263,8 @@ TEST_F(QuicSpdyServerStreamTest, InvalidHeadersWithFin) {
0x54, 0x54, 0x50, 0x2f, // TTP/
0x31, 0x2e, 0x31, // 1.1
};
- QuicStreamFrame frame(
- stream_->id(), true, 0, MakeIOVector(StringPiece(arr, arraysize(arr))));
+ StringPiece data(arr, arraysize(arr));
+ QuicStreamFrame frame(stream_->id(), true, 0, MakeIOVector(data));
// Verify that we don't crash when we get a invalid headers in stream frame.
stream_->OnStreamFrame(frame);
}
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.cc b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
index df9e378e722..9744ff89e53 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
@@ -17,6 +17,8 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
+#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/quic_server_session.h"
using base::StringPiece;
using std::make_pair;
@@ -26,23 +28,24 @@ namespace tools {
namespace {
-// Time period for which the guid should live in time wait state..
+// Time period for which the connection_id should live in time wait state..
const int kTimeWaitSeconds = 5;
} // namespace
// A very simple alarm that just informs the QuicTimeWaitListManager to clean
-// up old guids. This alarm should be unregistered and deleted before the
-// QuicTimeWaitListManager is deleted.
-class GuidCleanUpAlarm : public EpollAlarm {
+// up old connection_ids. This alarm should be unregistered and deleted before
+// the QuicTimeWaitListManager is deleted.
+class ConnectionIdCleanUpAlarm : public EpollAlarm {
public:
- explicit GuidCleanUpAlarm(QuicTimeWaitListManager* time_wait_list_manager)
+ explicit ConnectionIdCleanUpAlarm(
+ QuicTimeWaitListManager* time_wait_list_manager)
: time_wait_list_manager_(time_wait_list_manager) {
}
virtual int64 OnAlarm() OVERRIDE {
EpollAlarm::OnAlarm();
- time_wait_list_manager_->CleanUpOldGuids();
+ time_wait_list_manager_->CleanUpOldConnectionIds();
// Let the time wait manager register the alarm at appropriate time.
return 0;
}
@@ -52,19 +55,9 @@ class GuidCleanUpAlarm : public EpollAlarm {
QuicTimeWaitListManager* time_wait_list_manager_;
};
-struct QuicTimeWaitListManager::GuidAddTime {
- GuidAddTime(QuicGuid guid, const QuicTime& time)
- : guid(guid),
- time_added(time) {
- }
-
- QuicGuid guid;
- QuicTime time_added;
-};
-
// This class stores pending public reset packets to be sent to clients.
// server_address - server address on which a packet what was received for
-// a guid in time wait state.
+// a connection_id in time wait state.
// client_address - address of the client that sent that packet. Needed to send
// the public reset packet back to the client.
// packet - the pending public reset packet that is to be sent to the client.
@@ -93,174 +86,103 @@ class QuicTimeWaitListManager::QueuedPacket {
QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* epoll_server,
const QuicVersionVector& supported_versions)
- : framer_(supported_versions,
- QuicTime::Zero(), // unused
- true),
- epoll_server_(epoll_server),
+ : epoll_server_(epoll_server),
kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
- guid_clean_up_alarm_(new GuidCleanUpAlarm(this)),
- clock_(epoll_server),
+ connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
+ clock_(epoll_server_),
writer_(writer),
- is_write_blocked_(false) {
- framer_.set_visitor(this);
- SetGuidCleanUpAlarm();
+ visitor_(visitor) {
+ SetConnectionIdCleanUpAlarm();
}
QuicTimeWaitListManager::~QuicTimeWaitListManager() {
- guid_clean_up_alarm_->UnregisterIfRegistered();
- STLDeleteElements(&time_ordered_guid_list_);
+ connection_id_clean_up_alarm_->UnregisterIfRegistered();
STLDeleteElements(&pending_packets_queue_);
- for (GuidMapIterator it = guid_map_.begin(); it != guid_map_.end(); ++it) {
+ for (ConnectionIdMap::iterator it = connection_id_map_.begin();
+ it != connection_id_map_.end();
+ ++it) {
delete it->second.close_packet;
}
}
-void QuicTimeWaitListManager::AddGuidToTimeWait(
- QuicGuid guid,
+void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
+ QuicConnectionId connection_id,
QuicVersion version,
QuicEncryptedPacket* close_packet) {
- DCHECK(!IsGuidInTimeWait(guid));
- // Initialize the guid with 0 packets received.
- GuidData data(0, version, close_packet);
- guid_map_.insert(make_pair(guid, data));
- time_ordered_guid_list_.push_back(new GuidAddTime(guid,
- clock_.ApproximateNow()));
-}
-
-bool QuicTimeWaitListManager::IsGuidInTimeWait(QuicGuid guid) const {
- return guid_map_.find(guid) != guid_map_.end();
+ DVLOG(1) << "Adding " << connection_id << " to the time wait list.";
+ int num_packets = 0;
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ if (it != connection_id_map_.end()) { // Replace record if it is reinserted.
+ num_packets = it->second.num_packets;
+ delete it->second.close_packet;
+ connection_id_map_.erase(it);
+ }
+ ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
+ close_packet);
+ connection_id_map_.insert(make_pair(connection_id, data));
}
-void QuicTimeWaitListManager::ProcessPacket(
- const IPEndPoint& server_address,
- const IPEndPoint& client_address,
- QuicGuid guid,
- const QuicEncryptedPacket& packet) {
- DCHECK(IsGuidInTimeWait(guid));
- server_address_ = server_address;
- client_address_ = client_address;
-
- // Set the framer to the appropriate version for this GUID, before processing.
- QuicVersion version = GetQuicVersionFromGuid(guid);
- framer_.set_version(version);
-
- framer_.ProcessPacket(packet);
+bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
+ QuicConnectionId connection_id) const {
+ return ContainsKey(connection_id_map_, connection_id);
}
-QuicVersion QuicTimeWaitListManager::GetQuicVersionFromGuid(QuicGuid guid) {
- GuidMapIterator it = guid_map_.find(guid);
- DCHECK(it != guid_map_.end());
+QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
+ QuicConnectionId connection_id) {
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ DCHECK(it != connection_id_map_.end());
return (it->second).version;
}
-bool QuicTimeWaitListManager::OnCanWrite() {
- is_write_blocked_ = false;
- while (!is_write_blocked_ && !pending_packets_queue_.empty()) {
+void QuicTimeWaitListManager::OnCanWrite() {
+ while (!pending_packets_queue_.empty()) {
QueuedPacket* queued_packet = pending_packets_queue_.front();
- WriteToWire(queued_packet);
- if (!is_write_blocked_) {
- pending_packets_queue_.pop_front();
- delete queued_packet;
+ if (!WriteToWire(queued_packet)) {
+ return;
}
+ pending_packets_queue_.pop_front();
+ delete queued_packet;
}
-
- return !is_write_blocked_;
}
-void QuicTimeWaitListManager::OnError(QuicFramer* framer) {
- DLOG(INFO) << QuicUtils::ErrorToString(framer->error());
-}
-
-bool QuicTimeWaitListManager::OnProtocolVersionMismatch(
- QuicVersion received_version) {
- // Drop such packets whose version don't match.
- return false;
-}
-
-bool QuicTimeWaitListManager::OnUnauthenticatedHeader(
- const QuicPacketHeader& header) {
+void QuicTimeWaitListManager::ProcessPacket(
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
+ const QuicEncryptedPacket& /*packet*/) {
+ DCHECK(IsConnectionIdInTimeWait(connection_id));
+ DVLOG(1) << "Processing " << connection_id << " in time wait state.";
// TODO(satyamshekhar): Think about handling packets from different client
// addresses.
- GuidMapIterator it = guid_map_.find(header.public_header.guid);
- DCHECK(it != guid_map_.end());
+ ConnectionIdMap::iterator it = connection_id_map_.find(connection_id);
+ DCHECK(it != connection_id_map_.end());
// Increment the received packet count.
++((it->second).num_packets);
if (!ShouldSendResponse((it->second).num_packets)) {
- return false;
+ return;
}
if (it->second.close_packet) {
QueuedPacket* queued_packet =
- new QueuedPacket(server_address_,
- client_address_,
+ new QueuedPacket(server_address,
+ client_address,
it->second.close_packet->Clone());
// Takes ownership of the packet.
SendOrQueuePacket(queued_packet);
} else {
- // We don't need the packet anymore. Just tell the client what sequence
- // number we rejected.
- SendPublicReset(server_address_,
- client_address_,
- header.public_header.guid,
- header.packet_sequence_number);
+ SendPublicReset(server_address,
+ client_address,
+ connection_id,
+ sequence_number);
}
- // Never process the body of the packet in time wait state.
- return false;
-}
-
-bool QuicTimeWaitListManager::OnPacketHeader(const QuicPacketHeader& header) {
- DCHECK(false);
- return false;
-}
-
-void QuicTimeWaitListManager::OnRevivedPacket() {
- DCHECK(false);
-}
-
-void QuicTimeWaitListManager::OnFecProtectedPayload(StringPiece /*payload*/) {
- DCHECK(false);
-}
-
-bool QuicTimeWaitListManager::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnAckFrame(const QuicAckFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& /*frame*/) {
- DCHECK(false);
- return false;
}
-bool QuicTimeWaitListManager::OnRstStreamFrame(
- const QuicRstStreamFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnConnectionCloseFrame(
- const QuicConnectionCloseFrame & /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-bool QuicTimeWaitListManager::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
- DCHECK(false);
- return false;
-}
-
-void QuicTimeWaitListManager::OnFecData(const QuicFecData& /*fec*/) {
- DCHECK(false);
-}
-
-// Returns true if the number of packets received for this guid is a power of 2
-// to throttle the number of public reset packets we send to a client.
+// Returns true if the number of packets received for this connection_id is a
+// power of 2 to throttle the number of public reset packets we send to a
+// client.
bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
return (received_packet_count & (received_packet_count - 1)) == 0;
}
@@ -268,95 +190,100 @@ bool QuicTimeWaitListManager::ShouldSendResponse(int received_packet_count) {
void QuicTimeWaitListManager::SendPublicReset(
const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber rejected_sequence_number) {
QuicPublicResetPacket packet;
- packet.public_header.guid = guid;
+ packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = rejected_sequence_number;
- // TODO(satyamshekhar): generate a valid nonce for this guid.
+ // TODO(satyamshekhar): generate a valid nonce for this connection_id.
packet.nonce_proof = 1010101;
+ packet.client_address = client_address;
QueuedPacket* queued_packet = new QueuedPacket(
server_address,
client_address,
- QuicFramer::BuildPublicResetPacket(packet));
+ BuildPublicReset(packet));
// Takes ownership of the packet.
SendOrQueuePacket(queued_packet);
}
+QuicEncryptedPacket* QuicTimeWaitListManager::BuildPublicReset(
+ const QuicPublicResetPacket& packet) {
+ return QuicFramer::BuildPublicResetPacket(packet);
+}
+
// Either sends the packet and deletes it or makes pending queue the
// owner of the packet.
void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) {
- if (!is_write_blocked_) {
- // TODO(satyamshekhar): Handle packets that fail due to error other than
- // EAGAIN or EWOULDBLOCK.
- WriteToWire(packet);
- }
-
- if (is_write_blocked_) {
+ if (WriteToWire(packet)) {
+ delete packet;
+ } else {
// pending_packets_queue takes the ownership of the queued packet.
pending_packets_queue_.push_back(packet);
- } else {
- delete packet;
}
}
-void QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
- DCHECK(!is_write_blocked_);
+bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked(this);
+ return false;
+ }
WriteResult result = writer_->WritePacket(
queued_packet->packet()->data(),
queued_packet->packet()->length(),
queued_packet->server_address().address(),
- queued_packet->client_address(),
- this);
-
+ queued_packet->client_address());
if (result.status == WRITE_STATUS_BLOCKED) {
- is_write_blocked_ = true;
+ // If blocked and unbuffered, return false to retry sending.
+ DCHECK(writer_->IsWriteBlocked());
+ visitor_->OnWriteBlocked(this);
+ return writer_->IsWriteBlockedDataBuffered();
} else if (result.status == WRITE_STATUS_ERROR) {
LOG(WARNING) << "Received unknown error while sending reset packet to "
<< queued_packet->client_address().ToString() << ": "
<< strerror(result.error_code);
}
+ return true;
}
-void QuicTimeWaitListManager::SetGuidCleanUpAlarm() {
- guid_clean_up_alarm_->UnregisterIfRegistered();
+void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
+ connection_id_clean_up_alarm_->UnregisterIfRegistered();
int64 next_alarm_interval;
- if (!time_ordered_guid_list_.empty()) {
- GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
+ if (!connection_id_map_.empty()) {
+ QuicTime oldest_connection_id =
+ connection_id_map_.begin()->second.time_added;
QuicTime now = clock_.ApproximateNow();
- DCHECK(now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_);
- next_alarm_interval = oldest_guid->time_added
- .Add(kTimeWaitPeriod_)
- .Subtract(now)
- .ToMicroseconds();
+ if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
+ next_alarm_interval = oldest_connection_id.Add(kTimeWaitPeriod_)
+ .Subtract(now)
+ .ToMicroseconds();
+ } else {
+ LOG(ERROR) << "ConnectionId lingered for longer than kTimeWaitPeriod";
+ next_alarm_interval = 0;
+ }
} else {
- // No guids added so none will expire before kTimeWaitPeriod_.
+ // No connection_ids added so none will expire before kTimeWaitPeriod_.
next_alarm_interval = kTimeWaitPeriod_.ToMicroseconds();
}
- epoll_server_->RegisterAlarmApproximateDelta(next_alarm_interval,
- guid_clean_up_alarm_.get());
+ epoll_server_->RegisterAlarmApproximateDelta(
+ next_alarm_interval, connection_id_clean_up_alarm_.get());
}
-void QuicTimeWaitListManager::CleanUpOldGuids() {
+void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
QuicTime now = clock_.ApproximateNow();
- while (time_ordered_guid_list_.size() > 0) {
- DCHECK_EQ(time_ordered_guid_list_.size(), guid_map_.size());
- GuidAddTime* oldest_guid = time_ordered_guid_list_.front();
- if (now.Subtract(oldest_guid->time_added) < kTimeWaitPeriod_) {
+ while (!connection_id_map_.empty()) {
+ ConnectionIdMap::iterator it = connection_id_map_.begin();
+ QuicTime oldest_connection_id = it->second.time_added;
+ if (now.Subtract(oldest_connection_id) < kTimeWaitPeriod_) {
break;
}
- // This guid has lived its age, retire it now.
- GuidMapIterator it = guid_map_.find(oldest_guid->guid);
- DCHECK(it != guid_map_.end());
+ // This connection_id has lived its age, retire it now.
delete it->second.close_packet;
- guid_map_.erase(oldest_guid->guid);
- time_ordered_guid_list_.pop_front();
- delete oldest_guid;
+ connection_id_map_.erase(it);
}
- SetGuidCleanUpAlarm();
+ SetConnectionIdCleanUpAlarm();
}
} // namespace tools
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.h b/chromium/net/tools/quic/quic_time_wait_list_manager.h
index bb24f144a02..426f09f0872 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.h
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.h
@@ -2,195 +2,175 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Handles packets for guids in time wait state by discarding the packet and
-// sending the clients a public reset packet with exponential backoff.
+// Handles packets for connection_ids in time wait state by discarding the
+// packet and sending the clients a public reset packet with exponential
+// backoff.
#ifndef NET_TOOLS_QUIC_QUIC_TIME_WAIT_LIST_MANAGER_H_
#define NET_TOOLS_QUIC_QUIC_TIME_WAIT_LIST_MANAGER_H_
#include <deque>
+#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/strings/string_piece.h"
+#include "net/base/linked_hash_map.h"
#include "net/quic/quic_blocked_writer_interface.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
-#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_epoll_clock.h"
namespace net {
+
+class EpollServer;
+
namespace tools {
-class GuidCleanUpAlarm;
+class ConnectionIdCleanUpAlarm;
+class QuicServerSessionVisitor;
namespace test {
class QuicTimeWaitListManagerPeer;
} // namespace test
-// Maintains a list of all guids that have been recently closed. A guid lives in
-// this state for kTimeWaitPeriod. All packets received for guids in this state
-// are handed over to the QuicTimeWaitListManager by the QuicDispatcher.
-// Decides whether to send a public reset packet, a copy of the previously sent
-// connection close packet, or nothing to the client which sent a packet
-// with the guid in time wait state. After the guid expires its time wait
-// period, a new connection/session will be created if a packet is received
-// for this guid.
-class QuicTimeWaitListManager : public QuicBlockedWriterInterface,
- public QuicFramerVisitorInterface {
+// Maintains a list of all connection_ids that have been recently closed. A
+// connection_id lives in this state for kTimeWaitPeriod. All packets received
+// for connection_ids in this state are handed over to the
+// QuicTimeWaitListManager by the QuicDispatcher. Decides whether to send a
+// public reset packet, a copy of the previously sent connection close packet,
+// or nothing to the client which sent a packet with the connection_id in time
+// wait state. After the connection_id expires its time wait period, a new
+// connection/session will be created if a packet is received for this
+// connection_id.
+class QuicTimeWaitListManager : public QuicBlockedWriterInterface {
public:
// writer - the entity that writes to the socket. (Owned by the dispatcher)
+ // visitor - the entity that manages blocked writers. (The dispatcher)
// epoll_server - used to run clean up alarms. (Owned by the dispatcher)
QuicTimeWaitListManager(QuicPacketWriter* writer,
+ QuicServerSessionVisitor* visitor,
EpollServer* epoll_server,
const QuicVersionVector& supported_versions);
virtual ~QuicTimeWaitListManager();
- // Adds the given guid to time wait state for kTimeWaitPeriod. Henceforth,
- // any packet bearing this guid should not be processed while the guid remains
- // in this list. If a non-NULL |close_packet| is provided, it is sent again
- // when packets are received for added guids. If NULL, a public reset packet
- // is sent with the specified |version|. DCHECKs that guid is not already on
- // the list.
- void AddGuidToTimeWait(QuicGuid guid,
- QuicVersion version,
- QuicEncryptedPacket* close_packet); // Owned.
-
- // Returns true if the guid is in time wait state, false otherwise. Packets
- // received for this guid should not lead to creation of new QuicSessions.
- bool IsGuidInTimeWait(QuicGuid guid) const;
-
- // Called when a packet is received for a guid that is in time wait state.
- // Sends a public reset packet to the client which sent this guid. Sending
- // of the public reset packet is throttled by using exponential back off.
- // DCHECKs for the guid to be in time wait state.
- // virtual to override in tests.
+ // Adds the given connection_id to time wait state for kTimeWaitPeriod.
+ // Henceforth, any packet bearing this connection_id should not be processed
+ // while the connection_id remains in this list. If a non-NULL |close_packet|
+ // is provided, it is sent again when packets are received for added
+ // connection_ids. If NULL, a public reset packet is sent with the specified
+ // |version|. DCHECKs that connection_id is not already on the list.
+ void AddConnectionIdToTimeWait(QuicConnectionId connection_id,
+ QuicVersion version,
+ QuicEncryptedPacket* close_packet); // Owned.
+
+ // Returns true if the connection_id is in time wait state, false otherwise.
+ // Packets received for this connection_id should not lead to creation of new
+ // QuicSessions.
+ bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) const;
+
+ // Called when a packet is received for a connection_id that is in time wait
+ // state. Sends a public reset packet to the client which sent this
+ // connection_id. Sending of the public reset packet is throttled by using
+ // exponential back off. DCHECKs for the connection_id to be in time wait
+ // state. virtual to override in tests.
virtual void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
const QuicEncryptedPacket& packet);
// Called by the dispatcher when the underlying socket becomes writable again,
// since we might need to send pending public reset packets which we didn't
// send because the underlying socket was write blocked.
- virtual bool OnCanWrite() OVERRIDE;
-
- // Used to delete guid entries that have outlived their time wait period.
- void CleanUpOldGuids();
-
- // QuicFramerVisitorInterface
- virtual void OnError(QuicFramer* framer) OVERRIDE;
- virtual bool OnProtocolVersionMismatch(QuicVersion received_version) OVERRIDE;
- virtual bool OnUnauthenticatedHeader(const QuicPacketHeader& header) OVERRIDE;
- virtual void OnPacket() OVERRIDE {}
- virtual void OnPublicResetPacket(
- const QuicPublicResetPacket& /*packet*/) OVERRIDE {}
- virtual void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE {}
-
- virtual void OnPacketComplete() OVERRIDE {}
- // The following methods should never get called because we always return
- // false from OnUnauthenticatedHeader(). We never process the encrypted bytes.
- virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE;
- virtual void OnRevivedPacket() OVERRIDE;
- virtual void OnFecProtectedPayload(base::StringPiece /*payload*/) OVERRIDE;
- virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE;
- virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE;
- virtual bool OnCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE;
- virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE;
- virtual bool OnConnectionCloseFrame(
- const QuicConnectionCloseFrame & /*frame*/) OVERRIDE;
- virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE;
- virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE;
+ virtual void OnCanWrite() OVERRIDE;
+
+ // Used to delete connection_id entries that have outlived their time wait
+ // period.
+ void CleanUpOldConnectionIds();
+
+ // Given a ConnectionId that exists in the time wait list, returns the
+ // QuicVersion associated with it.
+ QuicVersion GetQuicVersionFromConnectionId(QuicConnectionId connection_id);
+
+ protected:
+ virtual QuicEncryptedPacket* BuildPublicReset(
+ const QuicPublicResetPacket& packet);
private:
friend class test::QuicTimeWaitListManagerPeer;
- // Stores the guid and the time it was added to time wait state.
- struct GuidAddTime;
// Internal structure to store pending public reset packets.
class QueuedPacket;
- // Decides if a packet should be sent for this guid based on the number of
- // received packets.
+ // Decides if a packet should be sent for this connection_id based on the
+ // number of received packets.
bool ShouldSendResponse(int received_packet_count);
- // Given a GUID that exists in the time wait list, returns the QuicVersion
- // associated with it. Used internally to set the framer version before
- // writing the public reset packet.
- QuicVersion GetQuicVersionFromGuid(QuicGuid guid);
-
// Creates a public reset packet and sends it or queues it to be sent later.
void SendPublicReset(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber rejected_sequence_number);
// Either sends the packet and deletes it or makes pending_packets_queue_ the
// owner of the packet.
void SendOrQueuePacket(QueuedPacket* packet);
- // Should only be called when write_blocked_ == false. We only care if the
- // writing was unsuccessful because the socket got blocked, which can be
- // tested using write_blocked_ == true. In case of all other errors we drop
- // the packet. Hence, we return void.
- void WriteToWire(QueuedPacket* packet);
+ // Sends the packet out. Returns true if the packet was successfully consumed.
+ // If the writer got blocked and did not buffer the packet, we'll need to keep
+ // the packet and retry sending. In case of all other errors we drop the
+ // packet.
+ bool WriteToWire(QueuedPacket* packet);
// Register the alarm with the epoll server to wake up at appropriate time.
- void SetGuidCleanUpAlarm();
-
- // A map from a recently closed guid to the number of packets received after
- // the termination of the connection bound to the guid.
- struct GuidData {
- GuidData(int num_packets_,
- QuicVersion version_,
- QuicEncryptedPacket* close_packet)
+ void SetConnectionIdCleanUpAlarm();
+
+ // A map from a recently closed connection_id to the number of packets
+ // received after the termination of the connection bound to the
+ // connection_id.
+ struct ConnectionIdData {
+ ConnectionIdData(int num_packets_,
+ QuicVersion version_,
+ QuicTime time_added_,
+ QuicEncryptedPacket* close_packet)
: num_packets(num_packets_),
version(version_),
+ time_added(time_added_),
close_packet(close_packet) {}
int num_packets;
QuicVersion version;
+ QuicTime time_added;
QuicEncryptedPacket* close_packet;
};
- base::hash_map<QuicGuid, GuidData> guid_map_;
- typedef base::hash_map<QuicGuid, GuidData>::iterator GuidMapIterator;
- // Maintains a list of GuidAddTime elements which it owns, in the
- // order they should be deleted.
- std::deque<GuidAddTime*> time_ordered_guid_list_;
+ // linked_hash_map allows lookup by ConnectionId and traversal in add order.
+ typedef linked_hash_map<QuicConnectionId, ConnectionIdData> ConnectionIdMap;
+ ConnectionIdMap connection_id_map_;
// Pending public reset packets that need to be sent out to the client
// when we are given a chance to write by the dispatcher.
std::deque<QueuedPacket*> pending_packets_queue_;
- // Used to parse incoming packets.
- QuicFramer framer_;
-
- // Server and client address of the last packet processed.
- IPEndPoint server_address_;
- IPEndPoint client_address_;
-
- // Used to schedule alarms to delete old guids which have been in the list for
- // too long. Owned by the dispatcher.
+ // Used to schedule alarms to delete old connection_ids which have been in the
+ // list for too long.
EpollServer* epoll_server_;
- // Time period for which guids should remain in time wait state.
+ // Time period for which connection_ids should remain in time wait state.
const QuicTime::Delta kTimeWaitPeriod_;
- // Alarm registered with the epoll server to clean up guids that have out
- // lived their duration in time wait state.
- scoped_ptr<GuidCleanUpAlarm> guid_clean_up_alarm_;
+ // Alarm registered with the epoll server to clean up connection_ids that have
+ // out lived their duration in time wait state.
+ scoped_ptr<ConnectionIdCleanUpAlarm> connection_id_clean_up_alarm_;
// Clock to efficiently measure approximate time from the epoll server.
QuicEpollClock clock_;
- // Interface that writes given buffer to the socket. Owned by the dispatcher.
+ // Interface that writes given buffer to the socket.
QuicPacketWriter* writer_;
- // True if the underlying udp socket is write blocked, i.e will return EAGAIN
- // on sendmsg.
- bool is_write_blocked_;
+ // Interface that manages blocked writers.
+ QuicServerSessionVisitor* visitor_;
DISALLOW_COPY_AND_ASSIGN(QuicTimeWaitListManager);
};
diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
index 22fd8ef4d06..67abd5928f7 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -14,37 +14,56 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/test_tools/mock_epoll_server.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using net::test::FramerVisitorCapturingPublicReset;
-using testing::_;
+using net::test::BuildUnsizedDataPacket;
+using net::test::NoOpFramerVisitor;
+using net::test::QuicVersionMax;
+using net::test::QuicVersionMin;
using testing::Args;
+using testing::Assign;
+using testing::DoAll;
using testing::Matcher;
using testing::MatcherInterface;
+using testing::NiceMock;
using testing::Return;
+using testing::ReturnPointee;
using testing::SetArgPointee;
+using testing::StrictMock;
using testing::Truly;
+using testing::_;
namespace net {
namespace tools {
namespace test {
-class QuicTimeWaitListManagerPeer {
+class FramerVisitorCapturingPublicReset : public NoOpFramerVisitor {
public:
- static QuicVersion version(QuicTimeWaitListManager* manager) {
- return manager->framer_.version();
+ FramerVisitorCapturingPublicReset() {}
+ virtual ~FramerVisitorCapturingPublicReset() OVERRIDE {}
+
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& public_reset) OVERRIDE {
+ public_reset_packet_ = public_reset;
}
- static bool is_write_blocked(QuicTimeWaitListManager* manager) {
- return manager->is_write_blocked_;
+ const QuicPublicResetPacket public_reset_packet() {
+ return public_reset_packet_;
}
+ private:
+ QuicPublicResetPacket public_reset_packet_;
+};
+
+class QuicTimeWaitListManagerPeer {
+ public:
static bool ShouldSendResponse(QuicTimeWaitListManager* manager,
- int received_packet_count) {
+ int received_packet_count) {
return manager->ShouldSendResponse(received_packet_count);
}
@@ -52,67 +71,72 @@ class QuicTimeWaitListManagerPeer {
return manager->kTimeWaitPeriod_;
}
- static QuicVersion GetQuicVersionFromGuid(QuicTimeWaitListManager* manager,
- QuicGuid guid) {
- return manager->GetQuicVersionFromGuid(guid);
+ static QuicVersion GetQuicVersionFromConnectionId(
+ QuicTimeWaitListManager* manager,
+ QuicConnectionId connection_id) {
+ return manager->GetQuicVersionFromConnectionId(connection_id);
}
};
namespace {
-class TestTimeWaitListManager : public QuicTimeWaitListManager {
- public:
- TestTimeWaitListManager(QuicPacketWriter* writer,
- EpollServer* epoll_server)
- : QuicTimeWaitListManager(writer, epoll_server, QuicSupportedVersions()) {
- }
-};
-
class MockFakeTimeEpollServer : public FakeTimeEpollServer {
public:
MOCK_METHOD2(RegisterAlarm, void(int64 timeout_in_us,
EpollAlarmCallbackInterface* alarm));
};
-class QuicTimeWaitListManagerTest : public testing::Test {
+class QuicTimeWaitListManagerTest : public ::testing::Test {
protected:
QuicTimeWaitListManagerTest()
- : time_wait_list_manager_(
- &writer_, &epoll_server_, QuicSupportedVersions()),
+ : time_wait_list_manager_(&writer_, &visitor_,
+ &epoll_server_, QuicSupportedVersions()),
framer_(QuicSupportedVersions(), QuicTime::Zero(), true),
- guid_(45) {
- }
+ connection_id_(45),
+ client_address_(net::test::TestPeerIPAddress(), kTestPort),
+ writer_is_blocked_(false) {}
- virtual ~QuicTimeWaitListManagerTest() {}
+ virtual ~QuicTimeWaitListManagerTest() OVERRIDE {}
- void AddGuid(QuicGuid guid) {
- AddGuid(guid, net::test::QuicVersionMax(), NULL);
+ virtual void SetUp() OVERRIDE {
+ EXPECT_CALL(writer_, IsWriteBlocked())
+ .WillRepeatedly(ReturnPointee(&writer_is_blocked_));
+ EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
+ .WillRepeatedly(Return(false));
}
- void AddGuid(QuicGuid guid,
- QuicVersion version,
- QuicEncryptedPacket* packet) {
- time_wait_list_manager_.AddGuidToTimeWait(guid, version, packet);
+ void AddConnectionId(QuicConnectionId connection_id) {
+ AddConnectionId(connection_id, QuicVersionMax(), NULL);
}
- bool IsGuidInTimeWait(QuicGuid guid) {
- return time_wait_list_manager_.IsGuidInTimeWait(guid);
+ void AddConnectionId(QuicConnectionId connection_id,
+ QuicVersion version,
+ QuicEncryptedPacket* packet) {
+ time_wait_list_manager_.AddConnectionIdToTimeWait(
+ connection_id, version, packet);
}
- void ProcessPacket(QuicGuid guid, const QuicEncryptedPacket& packet) {
+ bool IsConnectionIdInTimeWait(QuicConnectionId connection_id) {
+ return time_wait_list_manager_.IsConnectionIdInTimeWait(connection_id);
+ }
+
+ void ProcessPacket(QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number) {
+ QuicEncryptedPacket packet(NULL, 0);
time_wait_list_manager_.ProcessPacket(server_address_,
client_address_,
- guid,
+ connection_id,
+ sequence_number,
packet);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
EncryptionLevel level,
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber sequence_number) {
QuicPacketHeader header;
- header.public_header.guid = guid;
- header.public_header.guid_length = PACKET_8BYTE_GUID;
+ header.public_header.connection_id = connection_id;
+ header.public_header.connection_id_length = PACKET_8BYTE_CONNECTION_ID;
header.public_header.version_flag = false;
header.public_header.reset_flag = false;
header.public_header.sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER;
@@ -127,7 +151,7 @@ class QuicTimeWaitListManagerTest : public testing::Test {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
EXPECT_TRUE(packet != NULL);
QuicEncryptedPacket* encrypted = framer_.EncryptPacket(ENCRYPTION_NONE,
sequence_number,
@@ -136,26 +160,28 @@ class QuicTimeWaitListManagerTest : public testing::Test {
return encrypted;
}
- MockFakeTimeEpollServer epoll_server_;
- MockPacketWriter writer_;
+ NiceMock<MockFakeTimeEpollServer> epoll_server_;
+ StrictMock<MockPacketWriter> writer_;
+ StrictMock<MockQuicServerSessionVisitor> visitor_;
QuicTimeWaitListManager time_wait_list_manager_;
QuicFramer framer_;
- QuicGuid guid_;
+ QuicConnectionId connection_id_;
IPEndPoint server_address_;
IPEndPoint client_address_;
+ bool writer_is_blocked_;
};
class ValidatePublicResetPacketPredicate
: public MatcherInterface<const std::tr1::tuple<const char*, int> > {
public:
- explicit ValidatePublicResetPacketPredicate(QuicGuid guid,
+ explicit ValidatePublicResetPacketPredicate(QuicConnectionId connection_id,
QuicPacketSequenceNumber number)
- : guid_(guid), sequence_number_(number) {
+ : connection_id_(connection_id), sequence_number_(number) {
}
virtual bool MatchAndExplain(
const std::tr1::tuple<const char*, int> packet_buffer,
- testing::MatchResultListener* /* listener */) const {
+ testing::MatchResultListener* /* listener */) const OVERRIDE {
FramerVisitorCapturingPublicReset visitor;
QuicFramer framer(QuicSupportedVersions(),
QuicTime::Zero(),
@@ -165,119 +191,73 @@ class ValidatePublicResetPacketPredicate
std::tr1::get<1>(packet_buffer));
framer.ProcessPacket(encrypted);
QuicPublicResetPacket packet = visitor.public_reset_packet();
- return guid_ == packet.public_header.guid &&
+ return connection_id_ == packet.public_header.connection_id &&
packet.public_header.reset_flag && !packet.public_header.version_flag &&
- sequence_number_ == packet.rejected_sequence_number;
+ sequence_number_ == packet.rejected_sequence_number &&
+ net::test::TestPeerIPAddress() == packet.client_address.address() &&
+ kTestPort == packet.client_address.port();
}
- virtual void DescribeTo(::std::ostream* os) const { }
+ virtual void DescribeTo(::std::ostream* os) const OVERRIDE {}
- virtual void DescribeNegationTo(::std::ostream* os) const { }
+ virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE {}
private:
- QuicGuid guid_;
+ QuicConnectionId connection_id_;
QuicPacketSequenceNumber sequence_number_;
};
Matcher<const std::tr1::tuple<const char*, int> > PublicResetPacketEq(
- QuicGuid guid,
+ QuicConnectionId connection_id,
QuicPacketSequenceNumber sequence_number) {
- return MakeMatcher(new ValidatePublicResetPacketPredicate(guid,
+ return MakeMatcher(new ValidatePublicResetPacketPredicate(connection_id,
sequence_number));
}
-TEST_F(QuicTimeWaitListManagerTest, CheckGuidInTimeWait) {
- EXPECT_FALSE(IsGuidInTimeWait(guid_));
- AddGuid(guid_);
- EXPECT_TRUE(IsGuidInTimeWait(guid_));
+TEST_F(QuicTimeWaitListManagerTest, CheckConnectionIdInTimeWait) {
+ EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_));
+ AddConnectionId(connection_id_);
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
}
TEST_F(QuicTimeWaitListManagerTest, SendConnectionClose) {
size_t kConnectionCloseLength = 100;
- AddGuid(guid_,
- net::test::QuicVersionMax(),
- new QuicEncryptedPacket(
- new char[kConnectionCloseLength], kConnectionCloseLength, true));
+ AddConnectionId(
+ connection_id_,
+ QuicVersionMax(),
+ new QuicEncryptedPacket(
+ new char[kConnectionCloseLength], kConnectionCloseLength, true));
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
EXPECT_CALL(writer_, WritePacket(_, kConnectionCloseLength,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
+ client_address_))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
- ProcessPacket(guid_, *packet);
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
}
TEST_F(QuicTimeWaitListManagerTest, SendPublicReset) {
- AddGuid(guid_);
- const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
- EXPECT_CALL(writer_, WritePacket(_, _,
- server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid_,
- kRandomSequenceNumber)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
-
- ProcessPacket(guid_, *packet);
-}
-
-TEST_F(QuicTimeWaitListManagerTest, SendPublicResetUndecryptable) {
- AddGuid(guid_);
+ AddConnectionId(connection_id_);
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(
- ENCRYPTION_INITIAL, guid_, kRandomSequenceNumber));
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid_,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id_,
kRandomSequenceNumber)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
-
- ProcessPacket(guid_, *packet);
-}
-
-TEST_F(QuicTimeWaitListManagerTest, DropInvalidPacket) {
- AddGuid(guid_);
- const char buffer[] = "invalid";
- QuicEncryptedPacket packet(buffer, arraysize(buffer));
- // Will get called for a valid packet since received packet count = 1 (2 ^ 0).
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0);
- ProcessPacket(guid_, packet);
-}
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
-TEST_F(QuicTimeWaitListManagerTest, DropPublicResetPacket) {
- AddGuid(guid_);
- QuicPublicResetPacket packet;
- packet.public_header.guid = guid_;
- packet.public_header.version_flag = false;
- packet.public_header.reset_flag = true;
- packet.rejected_sequence_number = 239191;
- packet.nonce_proof = 1010101;
- scoped_ptr<QuicEncryptedPacket> public_reset_packet(
- QuicFramer::BuildPublicResetPacket(packet));
- // Will get called for a data packet since received packet count = 1 (2 ^ 0).
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(0);
- ProcessPacket(guid_, *public_reset_packet);
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
}
TEST_F(QuicTimeWaitListManagerTest, SendPublicResetWithExponentialBackOff) {
- AddGuid(guid_);
+ AddConnectionId(connection_id_);
for (int sequence_number = 1; sequence_number < 101; ++sequence_number) {
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, sequence_number));
if ((sequence_number & (sequence_number - 1)) == 0) {
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _))
+ EXPECT_CALL(writer_, WritePacket(_, _, _, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
}
- ProcessPacket(guid_, *packet);
+ ProcessPacket(connection_id_, sequence_number);
// Send public reset with exponential back off.
if ((sequence_number & (sequence_number - 1)) == 0) {
EXPECT_TRUE(QuicTimeWaitListManagerPeer::ShouldSendResponse(
@@ -289,157 +269,192 @@ TEST_F(QuicTimeWaitListManagerTest, SendPublicResetWithExponentialBackOff) {
}
}
-TEST_F(QuicTimeWaitListManagerTest, CleanUpOldGuids) {
- const int kGuidCount = 100;
- const int kOldGuidCount = 31;
+TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
+ const int kConnectionIdCount = 100;
+ const int kOldConnectionIdCount = 31;
- // Add guids such that their expiry time is kTimeWaitPeriod_.
+ // Add connection_ids such that their expiry time is kTimeWaitPeriod_.
epoll_server_.set_now_in_usec(0);
- for (int guid = 1; guid <= kOldGuidCount; ++guid) {
- AddGuid(guid);
+ for (int connection_id = 1;
+ connection_id <= kOldConnectionIdCount;
+ ++connection_id) {
+ AddConnectionId(connection_id);
}
- // Add remaining guids such that their add time is 2 * kTimeWaitPeriod.
+ // Add remaining connection_ids such that their add time is
+ // 2 * kTimeWaitPeriod.
const QuicTime::Delta time_wait_period =
QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
epoll_server_.set_now_in_usec(time_wait_period.ToMicroseconds());
- for (int guid = kOldGuidCount + 1; guid <= kGuidCount; ++guid) {
- AddGuid(guid);
+ for (int connection_id = kOldConnectionIdCount + 1;
+ connection_id <= kConnectionIdCount;
+ ++connection_id) {
+ AddConnectionId(connection_id);
}
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
- // After all the old guids are cleaned up, check the next alarm interval.
+ // After all the old connection_ids are cleaned up, check the next alarm
+ // interval.
int64 next_alarm_time = epoll_server_.ApproximateNowInUsec() +
time_wait_period.Subtract(offset).ToMicroseconds();
EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
- time_wait_list_manager_.CleanUpOldGuids();
- for (int guid = 1; guid <= kGuidCount; ++guid) {
- EXPECT_EQ(guid > kOldGuidCount, IsGuidInTimeWait(guid))
- << "kOldGuidCount: " << kOldGuidCount
- << " guid: " << guid;
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ for (int connection_id = 1;
+ connection_id <= kConnectionIdCount;
+ ++connection_id) {
+ EXPECT_EQ(connection_id > kOldConnectionIdCount,
+ IsConnectionIdInTimeWait(connection_id))
+ << "kOldConnectionIdCount: " << kOldConnectionIdCount
+ << " connection_id: " << connection_id;
}
}
TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) {
- QuicGuid guid = 1;
- AddGuid(guid);
+ QuicConnectionId connection_id = 1;
+ AddConnectionId(connection_id);
QuicPacketSequenceNumber sequence_number = 234;
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid, sequence_number));
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ ENCRYPTION_NONE, connection_id, sequence_number));
// Let first write through.
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
- ProcessPacket(guid, *packet);
- EXPECT_FALSE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
// write block for the next packet.
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
- .WillOnce(Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN)));
- ProcessPacket(guid, *packet);
+ .WillOnce(DoAll(
+ Assign(&writer_is_blocked_, true),
+ Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN))));
+ EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
// 3rd packet. No public reset should be sent;
- ProcessPacket(guid, *packet);
- EXPECT_TRUE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
+ ProcessPacket(connection_id, sequence_number);
- // write packet should not be called since already write blocked but the
+ // write packet should not be called since we are write blocked but the
// should be queued.
- QuicGuid other_guid = 2;
- AddGuid(other_guid);
+ QuicConnectionId other_connection_id = 2;
+ AddConnectionId(other_connection_id);
QuicPacketSequenceNumber other_sequence_number = 23423;
scoped_ptr<QuicEncryptedPacket> other_packet(
ConstructEncryptedPacket(
- ENCRYPTION_NONE, other_guid, other_sequence_number));
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _))
+ ENCRYPTION_NONE, other_connection_id, other_sequence_number));
+ EXPECT_CALL(writer_, WritePacket(_, _, _, _))
.Times(0);
- ProcessPacket(other_guid, *other_packet);
+ EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
+ ProcessPacket(other_connection_id, other_sequence_number);
// Now expect all the write blocked public reset packets to be sent again.
+ writer_is_blocked_ = false;
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id,
sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
EXPECT_CALL(writer_, WritePacket(_, _,
server_address_.address(),
- client_address_,
- &time_wait_list_manager_))
- .With(Args<0, 1>(PublicResetPacketEq(other_guid,
+ client_address_))
+ .With(Args<0, 1>(PublicResetPacketEq(other_connection_id,
other_sequence_number)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK,
other_packet->length())));
time_wait_list_manager_.OnCanWrite();
- EXPECT_FALSE(
- QuicTimeWaitListManagerPeer::is_write_blocked(&time_wait_list_manager_));
}
-TEST_F(QuicTimeWaitListManagerTest, MakeSureFramerUsesCorrectVersion) {
+TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
+ const int kConnectionId1 = 123;
+ const int kConnectionId2 = 456;
+ const int kConnectionId3 = 789;
+
+ AddConnectionId(kConnectionId1, QuicVersionMin(), NULL);
+ AddConnectionId(kConnectionId2, QuicVersionMax(), NULL);
+ AddConnectionId(kConnectionId3, QuicVersionMax(), NULL);
+
+ EXPECT_EQ(QuicVersionMin(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId1));
+ EXPECT_EQ(QuicVersionMax(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId2));
+ EXPECT_EQ(QuicVersionMax(),
+ QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId(
+ &time_wait_list_manager_, kConnectionId3));
+}
+
+TEST_F(QuicTimeWaitListManagerTest, AddConnectionIdTwice) {
+ // Add connection_ids such that their expiry time is kTimeWaitPeriod_.
+ epoll_server_.set_now_in_usec(0);
+ AddConnectionId(connection_id_);
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
+ size_t kConnectionCloseLength = 100;
+ AddConnectionId(
+ connection_id_,
+ QuicVersionMax(),
+ new QuicEncryptedPacket(
+ new char[kConnectionCloseLength], kConnectionCloseLength, true));
+ EXPECT_TRUE(IsConnectionIdInTimeWait(connection_id_));
+
+ EXPECT_CALL(writer_, WritePacket(_,
+ kConnectionCloseLength,
+ server_address_.address(),
+ client_address_))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
+
const int kRandomSequenceNumber = 1;
- scoped_ptr<QuicEncryptedPacket> packet;
+ ProcessPacket(connection_id_, kRandomSequenceNumber);
- AddGuid(guid_, net::test::QuicVersionMin(), NULL);
- framer_.set_version(net::test::QuicVersionMin());
- packet.reset(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
+ const QuicTime::Delta time_wait_period =
+ QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
- // Reset packet should be written, using the minimum quic version.
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- ProcessPacket(guid_, *packet);
- EXPECT_EQ(QuicTimeWaitListManagerPeer::version(&time_wait_list_manager_),
- net::test::QuicVersionMin());
-
- // New guid
- ++guid_;
-
- AddGuid(guid_, net::test::QuicVersionMax(), NULL);
- framer_.set_version(net::test::QuicVersionMax());
- packet.reset(
- ConstructEncryptedPacket(ENCRYPTION_NONE, guid_, kRandomSequenceNumber));
-
- // Reset packet should be written, using the maximum quic version.
- EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)).Times(1)
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- ProcessPacket(guid_, *packet);
- EXPECT_EQ(QuicTimeWaitListManagerPeer::version(&time_wait_list_manager_),
- net::test::QuicVersionMax());
-}
+ QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
+ // Now set the current time as time_wait_period + offset usecs.
+ epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ // After the connection_ids are cleaned up, check the next alarm interval.
+ int64 next_alarm_time = epoll_server_.ApproximateNowInUsec() +
+ time_wait_period.ToMicroseconds();
-TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
- const int kGuid1 = 123;
- const int kGuid2 = 456;
- const int kGuid3 = 789;
-
- AddGuid(kGuid1, net::test::QuicVersionMin(), NULL);
- AddGuid(kGuid2, net::test::QuicVersionMax(), NULL);
- AddGuid(kGuid3, net::test::QuicVersionMax(), NULL);
-
- EXPECT_EQ(net::test::QuicVersionMin(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid1));
- EXPECT_EQ(net::test::QuicVersionMax(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid2));
- EXPECT_EQ(net::test::QuicVersionMax(),
- QuicTimeWaitListManagerPeer::GetQuicVersionFromGuid(
- &time_wait_list_manager_, kGuid3));
+ EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ EXPECT_FALSE(IsConnectionIdInTimeWait(connection_id_));
}
+TEST_F(QuicTimeWaitListManagerTest, ConnectionIdsOrderedByTime) {
+ // Simple randomization: the values of connection_ids are swapped based on the
+ // current seconds on the clock. If the container is broken, the test will be
+ // 50% flaky.
+ int odd_second = static_cast<int>(epoll_server_.ApproximateNowInUsec()) % 2;
+ EXPECT_TRUE(odd_second == 0 || odd_second == 1);
+ const QuicConnectionId kConnectionId1 = odd_second;
+ const QuicConnectionId kConnectionId2 = 1 - odd_second;
+
+ // 1 will hash lower than 2, but we add it later. They should come out in the
+ // add order, not hash order.
+ epoll_server_.set_now_in_usec(0);
+ AddConnectionId(kConnectionId1);
+ epoll_server_.set_now_in_usec(10);
+ AddConnectionId(kConnectionId2);
+
+ const QuicTime::Delta time_wait_period =
+ QuicTimeWaitListManagerPeer::time_wait_period(&time_wait_list_manager_);
+ epoll_server_.set_now_in_usec(time_wait_period.ToMicroseconds() + 1);
+
+ EXPECT_CALL(epoll_server_, RegisterAlarm(_, _));
+
+ time_wait_list_manager_.CleanUpOldConnectionIds();
+ EXPECT_FALSE(IsConnectionIdInTimeWait(kConnectionId1));
+ EXPECT_TRUE(IsConnectionIdInTimeWait(kConnectionId2));
+}
} // namespace
} // namespace test
} // namespace tools
diff --git a/chromium/net/tools/quic/spdy_utils.cc b/chromium/net/tools/quic/spdy_utils.cc
index c350a96f9e2..7f146493671 100644
--- a/chromium/net/tools/quic/spdy_utils.cc
+++ b/chromium/net/tools/quic/spdy_utils.cc
@@ -38,8 +38,8 @@ void PopulateSpdyHeaderBlock(const BalsaHeaders& headers,
hi != headers.header_lines_end();
++hi) {
if ((hi->second.length() == 0) && !allow_empty_values) {
- DLOG(INFO) << "Dropping empty header " << hi->first.as_string()
- << " from headers";
+ DVLOG(1) << "Dropping empty header " << hi->first.as_string()
+ << " from headers";
continue;
}
@@ -157,8 +157,8 @@ string SpdyUtils::SerializeResponseHeaders(
// static
string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) {
- int length = SpdyFramer::GetSerializedLength(SPDY3, &headers);
- SpdyFrameBuilder builder(length);
+ size_t length = SpdyFramer::GetSerializedLength(SPDY3, &headers);
+ SpdyFrameBuilder builder(length, SPDY3);
SpdyFramer::WriteHeaderBlock(&builder, SPDY3, &headers);
scoped_ptr<SpdyFrame> block(builder.take());
return string(block->data(), length);
diff --git a/chromium/net/tools/quic/spdy_utils.h b/chromium/net/tools/quic/spdy_utils.h
index cfad5f1918b..e0ae4edb905 100644
--- a/chromium/net/tools/quic/spdy_utils.h
+++ b/chromium/net/tools/quic/spdy_utils.h
@@ -37,6 +37,9 @@ class SpdyUtils {
static std::string SerializeUncompressedHeaders(
const SpdyHeaderBlock& headers);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
};
} // namespace tools
diff --git a/chromium/net/tools/quic/test_tools/http_message_test_utils.cc b/chromium/net/tools/quic/test_tools/http_message.cc
index 70eb59290fa..9bd3cffc312 100644
--- a/chromium/net/tools/quic/test_tools/http_message_test_utils.cc
+++ b/chromium/net/tools/quic/test_tools/http_message.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 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 "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
#include <vector>
diff --git a/chromium/net/tools/quic/test_tools/http_message_test_utils.h b/chromium/net/tools/quic/test_tools/http_message.h
index fefdb4909cd..6b63dafd76c 100644
--- a/chromium/net/tools/quic/test_tools/http_message_test_utils.h
+++ b/chromium/net/tools/quic/test_tools/http_message.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.
-#ifndef NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
-#define NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
#include <string>
#include <vector>
@@ -130,4 +130,4 @@ class HTTPMessage {
} // namespace tools
} // namespace net
-#endif // NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_TEST_UTILS_H_
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
diff --git a/chromium/net/tools/quic/test_tools/mock_epoll_server.h b/chromium/net/tools/quic/test_tools/mock_epoll_server.h
index fbc16956d72..cdb6a36a7ce 100644
--- a/chromium/net/tools/quic/test_tools/mock_epoll_server.h
+++ b/chromium/net/tools/quic/test_tools/mock_epoll_server.h
@@ -43,6 +43,8 @@ class FakeTimeEpollServer : public EpollServer {
private:
int64 now_in_usec_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeTimeEpollServer);
};
class MockEpollServer : public FakeTimeEpollServer {
@@ -83,20 +85,22 @@ class MockEpollServer : public FakeTimeEpollServer {
protected: // functions
// These functions do nothing here, as we're not actually
// using the epoll_* syscalls.
- virtual void DelFD(int fd) const OVERRIDE { }
- virtual void AddFD(int fd, int event_mask) const OVERRIDE { }
- virtual void ModFD(int fd, int event_mask) const OVERRIDE { }
+ virtual void DelFD(int fd) const OVERRIDE {}
+ virtual void AddFD(int fd, int event_mask) const OVERRIDE {}
+ virtual void ModFD(int fd, int event_mask) const OVERRIDE {}
// Replaces the epoll_server's epoll_wait_impl.
virtual int epoll_wait_impl(int epfd,
struct epoll_event* events,
int max_events,
int timeout_in_ms) OVERRIDE;
- virtual void SetNonblocking (int fd) OVERRIDE { }
+ virtual void SetNonblocking (int fd) OVERRIDE {}
private: // members
EventQueue event_queue_;
int64 until_in_usec_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockEpollServer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
index 2d9c1ec184f..13271ca8afc 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
+++ b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.cc
@@ -4,6 +4,8 @@
#include "net/tools/quic/test_tools/mock_quic_dispatcher.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
namespace net {
namespace tools {
namespace test {
@@ -11,11 +13,12 @@ namespace test {
MockQuicDispatcher::MockQuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
- QuicGuid guid,
EpollServer* eps)
- : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), guid,
- eps) {
-}
+ : QuicDispatcher(config,
+ crypto_config,
+ QuicSupportedVersions(),
+ eps) {}
+
MockQuicDispatcher::~MockQuicDispatcher() {}
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
index 5f885e875b6..d1559115bf2 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
+++ b/chromium/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -21,15 +21,16 @@ class MockQuicDispatcher : public QuicDispatcher {
public:
MockQuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
- QuicGuid guid,
EpollServer* eps);
+
virtual ~MockQuicDispatcher();
- MOCK_METHOD5(ProcessPacket, void(const IPEndPoint& server_address,
+ MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- bool has_version_flag,
const QuicEncryptedPacket& packet));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockQuicDispatcher);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 11aafb69495..05a7385181f 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -10,8 +10,6 @@
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
-using net::test::QuicTestWriter;
-
namespace net {
namespace tools {
namespace test {
@@ -21,11 +19,11 @@ namespace test {
class WriteUnblockedAlarm : public QuicAlarm::Delegate {
public:
explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
- DCHECK(writer_->blocked_writer());
- writer_->blocked_writer()->OnCanWrite();
+ DVLOG(1) << "Unblocking socket.";
+ writer_->OnCanWrite();
return QuicTime::Zero();
}
@@ -37,8 +35,7 @@ class WriteUnblockedAlarm : public QuicAlarm::Delegate {
// later point.
class DelayAlarm : public QuicAlarm::Delegate {
public:
- explicit DelayAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
return writer_->ReleaseOldPackets();
@@ -50,7 +47,6 @@ class DelayAlarm : public QuicAlarm::Delegate {
PacketDroppingTestWriter::PacketDroppingTestWriter()
: clock_(NULL),
- blocked_writer_(NULL),
cur_buffer_size_(0),
config_mutex_(),
fake_packet_loss_percentage_(0),
@@ -60,45 +56,45 @@ PacketDroppingTestWriter::PacketDroppingTestWriter()
fake_bandwidth_(QuicBandwidth::Zero()),
buffer_size_(0) {
uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
- LOG(INFO) << "Seeding packet loss with " << seed;
+ VLOG(1) << "Seeding packet loss with " << seed;
simple_random_.set_seed(seed);
}
-PacketDroppingTestWriter::~PacketDroppingTestWriter() { }
+PacketDroppingTestWriter::~PacketDroppingTestWriter() {}
-void PacketDroppingTestWriter::SetConnectionHelper(
- QuicEpollConnectionHelper* helper) {
+void PacketDroppingTestWriter::Initialize(
+ QuicEpollConnectionHelper* helper,
+ Delegate* on_can_write) {
clock_ = helper->GetClock();
write_unblocked_alarm_.reset(
helper->CreateAlarm(new WriteUnblockedAlarm(this)));
delay_alarm_.reset(
helper->CreateAlarm(new DelayAlarm(this)));
+ on_can_write_.reset(on_can_write);
}
WriteResult PacketDroppingTestWriter::WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const net::IPAddressNumber& self_address,
- const net::IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) {
+ const net::IPEndPoint& peer_address) {
ReleaseOldPackets();
base::AutoLock locked(config_mutex_);
if (fake_packet_loss_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_packet_loss_percentage_)) {
- DLOG(INFO) << "Dropping packet.";
+ DVLOG(1) << "Dropping packet.";
return WriteResult(WRITE_STATUS_OK, buf_len);
}
if (fake_blocked_socket_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_blocked_socket_percentage_)) {
- DLOG(INFO) << "Blocking socket.";
+ CHECK(on_can_write_.get() != NULL);
+ DVLOG(1) << "Blocking socket.";
if (!write_unblocked_alarm_->IsSet()) {
- blocked_writer_ = blocked_writer;
- // Set the alarm for 1ms in the future.
- write_unblocked_alarm_->Set(
- clock_->ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(1)));
+ // Set the alarm to fire immediately.
+ write_unblocked_alarm_->Set(clock_->ApproximateNow());
}
return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
}
@@ -106,7 +102,7 @@ WriteResult PacketDroppingTestWriter::WritePacket(
if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
// Drop packets which do not fit into the buffer.
- DLOG(INFO) << "Dropping packet because the buffer is full.";
+ DVLOG(1) << "Dropping packet because the buffer is full.";
return WriteResult(WRITE_STATUS_OK, buf_len);
}
@@ -133,12 +129,22 @@ WriteResult PacketDroppingTestWriter::WritePacket(
return WriteResult(WRITE_STATUS_OK, buf_len);
}
- return writer()->WritePacket(buffer, buf_len, self_address, peer_address,
- blocked_writer);
+ return QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address, peer_address);
}
-bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const {
- return false;
+bool PacketDroppingTestWriter::IsWriteBlocked() const {
+ if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
+ return true;
+ }
+ return QuicPacketWriterWrapper::IsWriteBlocked();
+}
+
+void PacketDroppingTestWriter::SetWritable() {
+ if (write_unblocked_alarm_.get() != NULL && write_unblocked_alarm_->IsSet()) {
+ write_unblocked_alarm_->Cancel();
+ }
+ QuicPacketWriterWrapper::SetWritable();
}
QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
@@ -151,17 +157,18 @@ QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
simple_random_.RandUint64() % 100 <
static_cast<uint64>(fake_packet_reorder_percentage_)) {
- DLOG(INFO) << "Reordering packets.";
+ DVLOG(1) << "Reordering packets.";
++iter;
// Swap the send times when re-ordering packets.
delayed_packets_.begin()->send_time = iter->send_time;
}
- DLOG(INFO) << "Releasing packet. " << (delayed_packets_.size() - 1)
- << " remaining.";
+ DVLOG(1) << "Releasing packet. " << (delayed_packets_.size() - 1)
+ << " remaining.";
// Grab the next one off the queue and send it.
- writer()->WritePacket(iter->buffer.data(), iter->buffer.length(),
- iter->self_address, iter->peer_address, NULL);
+ QuicPacketWriterWrapper::WritePacket(
+ iter->buffer.data(), iter->buffer.length(),
+ iter->self_address, iter->peer_address);
DCHECK_GE(cur_buffer_size_, iter->buffer.length());
cur_buffer_size_ -= iter->buffer.length();
delayed_packets_.erase(iter);
@@ -184,6 +191,10 @@ QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
return QuicTime::Zero();
}
+void PacketDroppingTestWriter::OnCanWrite() {
+ on_can_write_->OnCanWrite();
+}
+
PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
const char* buffer,
size_t buf_len,
@@ -193,8 +204,7 @@ PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
: buffer(buffer, buf_len),
self_address(self_address),
peer_address(peer_address),
- send_time(send_time) {
-}
+ send_time(send_time) {}
PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {}
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 2a736e0cfe2..35097229cf3 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -7,14 +7,14 @@
#include <list>
+#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_clock.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/test_tools/quic_test_client.h"
#include "net/tools/quic/test_tools/quic_test_utils.h"
@@ -25,29 +25,41 @@ namespace test {
// Simulates a connection that drops packets a configured percentage of the time
// and has a blocked socket a configured percentage of the time. Also provides
// the options to delay packets and reorder packets if delay is enabled.
-class PacketDroppingTestWriter : public net::test::QuicTestWriter {
+class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual void OnCanWrite() = 0;
+ };
+
PacketDroppingTestWriter();
virtual ~PacketDroppingTestWriter();
- void SetConnectionHelper(QuicEpollConnectionHelper* helper);
+ // Must be called before blocking, reordering or delaying (loss is OK). May be
+ // called after connecting if the helper is not available before.
+ // |on_can_write| will be triggered when fake-unblocking; ownership will be
+ // assumed.
+ void Initialize(QuicEpollConnectionHelper* helper, Delegate* on_can_write);
// QuicPacketWriter methods:
virtual WriteResult WritePacket(
- const char* buffer, size_t buf_len,
+ const char* buffer,
+ size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE;
+ const IPEndPoint& peer_address) OVERRIDE;
+
+ virtual bool IsWriteBlocked() const OVERRIDE;
- virtual bool IsWriteBlockedDataBuffered() const OVERRIDE;
+ virtual void SetWritable() OVERRIDE;
// Writes out any packet which should have been sent by now
// to the contained writer and returns the time
// for the next delayed packet to be written.
QuicTime ReleaseOldPackets();
- QuicBlockedWriterInterface* blocked_writer() { return blocked_writer_; }
+ void OnCanWrite();
// The percent of time a packet is simulated as being lost.
void set_fake_packet_loss_percentage(int32 fake_packet_loss_percentage) {
@@ -102,7 +114,7 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter {
QuicTime ReleaseNextPacket();
// A single packet which will be sent at the supplied send_time.
- class DelayedWrite {
+ struct DelayedWrite {
public:
DelayedWrite(const char* buffer,
size_t buf_len,
@@ -122,8 +134,8 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter {
const QuicClock* clock_;
scoped_ptr<QuicAlarm> write_unblocked_alarm_;
scoped_ptr<QuicAlarm> delay_alarm_;
- QuicBlockedWriterInterface* blocked_writer_;
- SimpleRandom simple_random_;
+ scoped_ptr<Delegate> on_can_write_;
+ net::test::SimpleRandom simple_random_;
// Stored packets delayed by fake packet delay or bandwidth restrictions.
DelayedPacketList delayed_packets_;
QuicByteCount cur_buffer_size_;
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.cc b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
index 25fdb7eedc5..89f1c82650c 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
@@ -11,8 +11,18 @@ namespace tools {
namespace test {
// static
-int QuicClientPeer::GetFd(QuicClient* client) {
- return client->fd_;
+QuicCryptoClientConfig* QuicClientPeer::GetCryptoConfig(QuicClient* client) {
+ return &client->crypto_config_;
+}
+
+// static
+bool QuicClientPeer::CreateUDPSocket(QuicClient* client) {
+ return client->CreateUDPSocket();
+}
+
+// static
+void QuicClientPeer::SetClientPort(QuicClient* client, int port) {
+ client->client_address_ = IPEndPoint(client->client_address_.address(), port);
}
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.h b/chromium/net/tools/quic/test_tools/quic_client_peer.h
index 016120aa8bf..b26fc6d829c 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.h
@@ -5,7 +5,12 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+#include "base/basictypes.h"
+
namespace net {
+
+class QuicCryptoClientConfig;
+
namespace tools {
class QuicClient;
@@ -14,7 +19,12 @@ namespace test {
class QuicClientPeer {
public:
- static int GetFd(QuicClient* client);
+ static QuicCryptoClientConfig* GetCryptoConfig(QuicClient* client);
+ static bool CreateUDPSocket(QuicClient* client);
+ static void SetClientPort(QuicClient* client, int port);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicClientPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
index c96eafd57e5..cd27802f512 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -5,8 +5,7 @@
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/quic_dispatcher.h"
-
-using net::test::QuicTestWriter;
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
namespace net {
namespace tools {
@@ -20,13 +19,8 @@ void QuicDispatcherPeer::SetTimeWaitListManager(
}
// static
-void QuicDispatcherPeer::SetWriteBlocked(QuicDispatcher* dispatcher) {
- dispatcher->write_blocked_ = true;
-}
-
-// static
void QuicDispatcherPeer::UseWriter(QuicDispatcher* dispatcher,
- QuicTestWriter* writer) {
+ QuicPacketWriterWrapper* writer) {
writer->set_writer(dispatcher->writer_.release());
dispatcher->writer_.reset(writer);
}
@@ -42,6 +36,17 @@ QuicEpollConnectionHelper* QuicDispatcherPeer::GetHelper(
return dispatcher->helper_.get();
}
+// static
+QuicConnection* QuicDispatcherPeer::CreateQuicConnection(
+ QuicDispatcher* dispatcher,
+ QuicConnectionId connection_id,
+ const IPEndPoint& server,
+ const IPEndPoint& client) {
+ return dispatcher->CreateQuicConnection(connection_id,
+ server,
+ client);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
index f463453f17a..45125c251d2 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -5,11 +5,15 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
-#include "net/quic/test_tools/quic_test_writer.h"
#include "net/tools/quic/quic_dispatcher.h"
+#include "net/base/ip_endpoint.h"
+
namespace net {
namespace tools {
+
+class QuicPacketWriterWrapper;
+
namespace test {
class QuicDispatcherPeer {
@@ -18,14 +22,22 @@ class QuicDispatcherPeer {
QuicDispatcher* dispatcher,
QuicTimeWaitListManager* time_wait_list_manager);
- static void SetWriteBlocked(QuicDispatcher* dispatcher);
-
+ // Injects |writer| into |dispatcher| as the top level writer.
static void UseWriter(QuicDispatcher* dispatcher,
- net::test::QuicTestWriter* writer);
+ QuicPacketWriterWrapper* writer);
static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher);
static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher);
+
+ static QuicConnection* CreateQuicConnection(
+ QuicDispatcher* dispatcher,
+ QuicConnectionId connection_id,
+ const IPEndPoint& server,
+ const IPEndPoint& client);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_server_peer.cc b/chromium/net/tools/quic/test_tools/quic_server_peer.cc
index 15f31297d17..33a086f2096 100644
--- a/chromium/net/tools/quic/test_tools/quic_server_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_server_peer.cc
@@ -28,11 +28,6 @@ QuicDispatcher* QuicServerPeer::GetDispatcher(QuicServer* server) {
return server->dispatcher_.get();
}
-// static
-int QuicServerPeer::GetFD(QuicServer* server) {
- return server->fd_;
-}
-
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_server_peer.h b/chromium/net/tools/quic/test_tools/quic_server_peer.h
index 65e2c5e96b2..f5f625db74f 100644
--- a/chromium/net/tools/quic/test_tools/quic_server_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_server_peer.h
@@ -5,6 +5,8 @@
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+#include "base/basictypes.h"
+
namespace net {
namespace tools {
@@ -19,7 +21,9 @@ class QuicServerPeer {
static bool SetSmallSocket(QuicServer* server);
static void DisableRecvmmsg(QuicServer* server);
static QuicDispatcher* GetDispatcher(QuicServer* server);
- static int GetFD(QuicServer* server);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicServerPeer);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.cc b/chromium/net/tools/quic/test_tools/quic_test_client.cc
index 57edadeec70..3e77bb51d6d 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.cc
@@ -10,39 +10,49 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
#include "net/quic/crypto/proof_verifier.h"
+#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
-#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/http_message.h"
+#include "net/tools/quic/test_tools/quic_client_peer.h"
#include "url/gurl.h"
using base::StringPiece;
+using net::QuicServerId;
using net::test::QuicConnectionPeer;
-using net::test::QuicTestWriter;
+using net::test::QuicSessionPeer;
+using net::test::ReliableQuicStreamPeer;
using std::string;
using std::vector;
+namespace net {
+namespace tools {
+namespace test {
namespace {
// RecordingProofVerifier accepts any certificate chain and records the common
// name of the leaf.
-class RecordingProofVerifier : public net::ProofVerifier {
+class RecordingProofVerifier : public ProofVerifier {
public:
// ProofVerifier interface.
- virtual net::ProofVerifier::Status VerifyProof(
+ virtual QuicAsyncStatus VerifyProof(
const string& hostname,
const string& server_config,
const vector<string>& certs,
const string& signature,
+ const ProofVerifyContext* context,
string* error_details,
- scoped_ptr<net::ProofVerifyDetails>* details,
- net::ProofVerifierCallback* callback) OVERRIDE {
- delete callback;
-
+ scoped_ptr<ProofVerifyDetails>* details,
+ ProofVerifierCallback* callback) OVERRIDE {
common_name_.clear();
if (certs.empty()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
// Convert certs to X509Certificate.
@@ -53,11 +63,11 @@ class RecordingProofVerifier : public net::ProofVerifier {
scoped_refptr<net::X509Certificate> cert =
net::X509Certificate::CreateFromDERCertChain(cert_pieces);
if (!cert.get()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
common_name_ = cert->subject().GetDisplayName();
- return SUCCESS;
+ return QUIC_SUCCESS;
}
const string& common_name() const { return common_name_; }
@@ -68,10 +78,6 @@ class RecordingProofVerifier : public net::ProofVerifier {
} // anonymous namespace
-namespace net {
-namespace tools {
-namespace test {
-
BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
bool secure) {
StringPiece uri = const_headers->request_uri();
@@ -94,101 +100,130 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
return headers;
}
-// A quic client which allows mocking out writes.
-class QuicEpollClient : public QuicClient {
- public:
- typedef QuicClient Super;
-
- QuicEpollClient(IPEndPoint server_address,
- const string& server_hostname,
- const QuicVersionVector& supported_versions)
- : Super(server_address, server_hostname, supported_versions, false),
- override_guid_(0), test_writer_(NULL) {
- }
-
- QuicEpollClient(IPEndPoint server_address,
- const string& server_hostname,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : Super(server_address, server_hostname, config, supported_versions),
- override_guid_(0), test_writer_(NULL) {
- }
-
- virtual ~QuicEpollClient() {
- if (connected()) {
- Disconnect();
- }
- }
-
- virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE {
- QuicPacketWriter* writer = Super::CreateQuicPacketWriter();
- if (!test_writer_) {
- return writer;
- }
- test_writer_->set_writer(writer);
- return test_writer_;
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server)
+ : QuicClient(server_address,
+ server_id,
+ supported_versions,
+ false,
+ epoll_server),
+ override_connection_id_(0),
+ test_writer_(NULL) {}
+
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server)
+ : QuicClient(server_address,
+ server_id,
+ supported_versions,
+ false,
+ config,
+ epoll_server),
+ override_connection_id_(0),
+ test_writer_(NULL) {}
+
+MockableQuicClient::~MockableQuicClient() {
+ if (connected()) {
+ Disconnect();
}
+}
- virtual QuicGuid GenerateGuid() OVERRIDE {
- return override_guid_ ? override_guid_ : Super::GenerateGuid();
+QuicPacketWriter* MockableQuicClient::CreateQuicPacketWriter() {
+ QuicPacketWriter* writer = QuicClient::CreateQuicPacketWriter();
+ if (!test_writer_) {
+ return writer;
}
+ test_writer_->set_writer(writer);
+ return test_writer_;
+}
- // Takes ownership of writer.
- void UseWriter(QuicTestWriter* writer) { test_writer_ = writer; }
-
- void UseGuid(QuicGuid guid) {
- override_guid_ = guid;
- }
+QuicConnectionId MockableQuicClient::GenerateConnectionId() {
+ return override_connection_id_ ? override_connection_id_
+ : QuicClient::GenerateConnectionId();
+}
- private:
- QuicGuid override_guid_; // GUID to use, if nonzero
- QuicTestWriter* test_writer_;
-};
+// Takes ownership of writer.
+void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
+ CHECK(test_writer_ == NULL);
+ test_writer_ = writer;
+}
-QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname,
- const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, supported_versions)) {
- Initialize(address, hostname, true);
+void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
+ override_connection_id_ = connection_id;
}
-QuicTestClient::QuicTestClient(IPEndPoint address,
- const string& hostname,
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicVersionVector& supported_versions)
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ false,
+ PRIVACY_MODE_DISABLED),
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(true);
+}
+
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
bool secure,
const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, supported_versions)) {
- Initialize(address, hostname, secure);
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ secure,
+ PRIVACY_MODE_DISABLED),
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(secure);
+}
+
+QuicTestClient::QuicTestClient(
+ IPEndPoint server_address,
+ const string& server_hostname,
+ bool secure,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions)
+ : client_(
+ new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ secure,
+ PRIVACY_MODE_DISABLED),
+ config,
+ supported_versions,
+ &epoll_server_)) {
+ Initialize(secure);
+}
+
+QuicTestClient::QuicTestClient() {
}
-QuicTestClient::QuicTestClient(IPEndPoint address,
- const string& hostname,
- bool secure,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : client_(new QuicEpollClient(address, hostname, config,
- supported_versions)) {
- Initialize(address, hostname, secure);
+QuicTestClient::~QuicTestClient() {
+ if (stream_) {
+ stream_->set_visitor(NULL);
+ }
}
-void QuicTestClient::Initialize(IPEndPoint address,
- const string& hostname,
- bool secure) {
- server_address_ = address;
+void QuicTestClient::Initialize(bool secure) {
priority_ = 3;
connect_attempted_ = false;
secure_ = secure;
auto_reconnect_ = false;
buffer_body_ = true;
+ fec_policy_ = FEC_PROTECT_OPTIONAL;
proof_verifier_ = NULL;
ClearPerRequestState();
ExpectCertificates(secure_);
}
-QuicTestClient::~QuicTestClient() {
- if (stream_) {
- stream_->set_visitor(NULL);
- }
-}
-
void QuicTestClient::ExpectCertificates(bool on) {
if (on) {
proof_verifier_ = new RecordingProofVerifier;
@@ -199,8 +234,14 @@ void QuicTestClient::ExpectCertificates(bool on) {
}
}
+void QuicTestClient::SetUserAgentID(const string& user_agent_id) {
+ client_->SetUserAgentID(user_agent_id);
+}
+
ssize_t QuicTestClient::SendRequest(const string& uri) {
- HTTPMessage message(HttpConstants::HTTP_1_1, HttpConstants::GET, uri);
+ HTTPMessage message(HttpConstants::HTTP_1_1,
+ HttpConstants::GET,
+ uri);
return SendMessage(message);
}
@@ -211,7 +252,11 @@ ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
if (!connected()) {
GURL url(message.headers()->request_uri().as_string());
if (!url.host().empty()) {
- client_->set_server_hostname(url.host());
+ client_->set_server_id(
+ QuicServerId(url.host(),
+ url.EffectiveIntPort(),
+ url.SchemeIs("https"),
+ PRIVACY_MODE_DISABLED));
}
}
@@ -236,6 +281,34 @@ ssize_t QuicTestClient::SendData(string data, bool last_data) {
return data.length();
}
+bool QuicTestClient::response_complete() const {
+ return response_complete_;
+}
+
+int QuicTestClient::response_header_size() const {
+ return response_header_size_;
+}
+
+int64 QuicTestClient::response_body_size() const {
+ return response_body_size_;
+}
+
+bool QuicTestClient::buffer_body() const {
+ return buffer_body_;
+}
+
+void QuicTestClient::set_buffer_body(bool buffer_body) {
+ buffer_body_ = buffer_body;
+}
+
+bool QuicTestClient::ServerInLameDuckMode() const {
+ return false;
+}
+
+const string& QuicTestClient::response_body() {
+ return response_;
+}
+
string QuicTestClient::SendCustomSynchronousRequest(
const HTTPMessage& message) {
SendMessage(message);
@@ -268,26 +341,39 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
}
stream_->set_visitor(this);
reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
+ // Set FEC policy on stream.
+ ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_);
}
return stream_;
}
+QuicErrorCode QuicTestClient::connection_error() {
+ return client()->session()->error();
+}
+
+MockableQuicClient* QuicTestClient::client() { return client_.get(); }
+
const string& QuicTestClient::cert_common_name() const {
return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_)
->common_name();
}
-bool QuicTestClient::connected() const {
- return client_->connected();
+QuicTagValueMap QuicTestClient::GetServerConfig() const {
+ QuicCryptoClientConfig* config =
+ QuicClientPeer::GetCryptoConfig(client_.get());
+ QuicCryptoClientConfig::CachedState* state =
+ config->LookupOrCreate(client_->server_id());
+ const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
+ if (handshake_msg != NULL) {
+ return handshake_msg->tag_value_map();
+ } else {
+ return QuicTagValueMap();
+ }
}
-void QuicTestClient::WaitForResponse() {
- if (stream_ == NULL) {
- // The client has likely disconnected.
- return;
- }
- client_->WaitForStreamToClose(stream_->id());
+bool QuicTestClient::connected() const {
+ return client_->connected();
}
void QuicTestClient::Connect() {
@@ -328,9 +414,9 @@ void QuicTestClient::ClearPerRequestState() {
void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+ int64 old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(timeout_us);
+ epoll_server()->set_timeout_in_us(timeout_us);
}
const QuicClock* clock =
QuicConnectionPeer::GetHelper(client()->session()->connection())->
@@ -343,15 +429,15 @@ void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+ epoll_server()->set_timeout_in_us(old_timeout_us);
}
}
void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
int64 timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64 old_timeout_us = client()->epoll_server()->timeout_in_us();
+ int64 old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(timeout_us);
+ epoll_server()->set_timeout_in_us(timeout_us);
}
const QuicClock* clock =
QuicConnectionPeer::GetHelper(client()->session()->connection())->
@@ -365,7 +451,7 @@ void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
- client()->epoll_server()->set_timeout_in_us(old_timeout_us);
+ epoll_server()->set_timeout_in_us(old_timeout_us);
}
}
@@ -389,7 +475,7 @@ const BalsaHeaders* QuicTestClient::response_headers() const {
}
}
-int QuicTestClient::response_size() const {
+int64 QuicTestClient::response_size() const {
return bytes_read_;
}
@@ -413,28 +499,71 @@ void QuicTestClient::OnClose(QuicDataStream* stream) {
response_headers_complete_ = stream_->headers_decompressed();
headers_.CopyFrom(stream_->headers());
stream_error_ = stream_->stream_error();
- bytes_read_ = stream_->stream_bytes_read();
- bytes_written_ = stream_->stream_bytes_written();
+ bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read();
+ bytes_written_ =
+ stream_->stream_bytes_written() + stream_->header_bytes_written();
response_header_size_ = headers_.GetSizeForWriteBuffer();
response_body_size_ = stream_->data().size();
stream_ = NULL;
}
-void QuicTestClient::UseWriter(QuicTestWriter* writer) {
- reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer);
+void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
+ client_->UseWriter(writer);
}
-void QuicTestClient::UseGuid(QuicGuid guid) {
+void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) {
DCHECK(!connected());
- reinterpret_cast<QuicEpollClient*>(client_.get())->UseGuid(guid);
+ client_->UseConnectionId(connection_id);
+}
+
+ssize_t QuicTestClient::SendAndWaitForResponse(const void *buffer,
+ size_t size) {
+ LOG(DFATAL) << "Not implemented";
+ return 0;
+}
+
+void QuicTestClient::Bind(IPEndPoint* local_address) {
+ DLOG(WARNING) << "Bind will be done during connect";
+}
+
+string QuicTestClient::SerializeMessage(const HTTPMessage& message) {
+ LOG(DFATAL) << "Not implemented";
+ return "";
+}
+
+IPAddressNumber QuicTestClient::bind_to_address() const {
+ return client_->bind_to_address();
+}
+
+void QuicTestClient::set_bind_to_address(IPAddressNumber address) {
+ client_->set_bind_to_address(address);
+}
+
+const IPEndPoint& QuicTestClient::address() const {
+ LOG(DFATAL) << "Not implemented";
+ return client_->server_address();
+}
+
+size_t QuicTestClient::requests_sent() const {
+ LOG(DFATAL) << "Not implemented";
+ return 0;
}
void QuicTestClient::WaitForWriteToFlush() {
- while (connected() && client()->session()->HasQueuedData()) {
+ while (connected() && client()->session()->HasDataToWrite()) {
client_->WaitForEvents();
}
}
+void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) {
+ fec_policy_ = fec_policy;
+ // Set policy for headers and crypto streams.
+ ReliableQuicStreamPeer::SetFecPolicy(
+ QuicSessionPeer::GetHeadersStream(client()->session()), fec_policy);
+ ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(),
+ fec_policy);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.h b/chromium/net/tools/quic/test_tools/quic_test_client.h
index e67a2a159bb..93c0352bca6 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.h
@@ -2,18 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
-#define NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "net/base/ip_endpoint.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/test_tools/quic_test_writer.h"
+#include "net/tools/balsa/balsa_frame.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
+#include "net/tools/quic/test_tools/simple_client.h"
namespace net {
@@ -21,14 +24,46 @@ class ProofVerifier;
namespace tools {
+class QuicPacketWriterWrapper;
+
namespace test {
class HTTPMessage;
+class MockableQuicClient;
-// A toy QUIC client used for testing.
-class QuicTestClient : public QuicDataStream::Visitor {
+// A quic client which allows mocking out writes.
+class MockableQuicClient : public QuicClient {
public:
- QuicTestClient(IPEndPoint server_address, const string& server_hostname,
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server);
+
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server);
+
+ virtual ~MockableQuicClient() OVERRIDE;
+ virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE;
+ virtual QuicConnectionId GenerateConnectionId() OVERRIDE;
+ void UseWriter(QuicPacketWriterWrapper* writer);
+ void UseConnectionId(QuicConnectionId connection_id);
+
+ private:
+ QuicConnectionId override_connection_id_; // ConnectionId to use, if nonzero
+ QuicPacketWriterWrapper* test_writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockableQuicClient);
+};
+
+// A toy QUIC client used for testing, mostly following the SimpleClient APIs.
+class QuicTestClient : public SimpleClient,
+ public QuicDataStream::Visitor {
+ public:
+ QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
const QuicVersionVector& supported_versions);
QuicTestClient(IPEndPoint server_address,
const string& server_hostname,
@@ -47,77 +82,99 @@ class QuicTestClient : public QuicDataStream::Visitor {
// name is recorded and available with |cert_common_name()|.
void ExpectCertificates(bool on);
- // 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 string& uri);
- ssize_t SendMessage(const HTTPMessage& message);
-
- string SendCustomSynchronousRequest(const HTTPMessage& message);
- string SendSynchronousRequest(const string& uri);
+ // Sets the |user_agent_id| of the |client_|.
+ void SetUserAgentID(const string& user_agent_id);
// Wraps data in a quic packet and sends it.
ssize_t SendData(string data, bool last_data);
- QuicPacketCreator::Options* options() { return client_->options(); }
-
- void WaitForResponse();
-
- void Connect();
- void ResetConnection();
- void Disconnect();
- IPEndPoint LocalSocketAddress() const;
- void ClearPerRequestState();
- void WaitForResponseForMs(int timeout_ms);
- void WaitForInitialResponseForMs(int timeout_ms);
- ssize_t Send(const void *buffer, size_t size);
- bool response_complete() const { return response_complete_; }
- bool response_headers_complete() const;
- const BalsaHeaders* response_headers() const;
- int response_size() const;
- int response_header_size() const { return response_header_size_; }
- int response_body_size() const { return response_body_size_; }
- size_t bytes_read() const;
- size_t bytes_written() const;
- bool buffer_body() const { return buffer_body_; }
- void set_buffer_body(bool buffer_body) { buffer_body_ = buffer_body; }
+ // From 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.
+ virtual ssize_t SendRequest(const string& uri) OVERRIDE;
+ virtual ssize_t SendMessage(const HTTPMessage& message) OVERRIDE;
+ virtual string SendCustomSynchronousRequest(
+ const HTTPMessage& message) OVERRIDE;
+ virtual string SendSynchronousRequest(const string& uri) OVERRIDE;
+ virtual void Connect() OVERRIDE;
+ virtual void ResetConnection() OVERRIDE;
+ virtual void Disconnect() OVERRIDE;
+ virtual IPEndPoint LocalSocketAddress() const OVERRIDE;
+ virtual void ClearPerRequestState() OVERRIDE;
+ virtual void WaitForResponseForMs(int timeout_ms) OVERRIDE;
+ virtual void WaitForInitialResponseForMs(int timeout_ms) OVERRIDE;
+ virtual ssize_t Send(const void *buffer, size_t size) OVERRIDE;
+ virtual bool response_complete() const OVERRIDE;
+ virtual bool response_headers_complete() const OVERRIDE;
+ virtual const BalsaHeaders* response_headers() const OVERRIDE;
+ virtual int64 response_size() const OVERRIDE;
+ virtual int response_header_size() const OVERRIDE;
+ virtual int64 response_body_size() const OVERRIDE;
+ virtual size_t bytes_read() const OVERRIDE;
+ virtual size_t bytes_written() const OVERRIDE;
+ virtual bool buffer_body() const OVERRIDE;
+ virtual void set_buffer_body(bool buffer_body) OVERRIDE;
+ virtual bool ServerInLameDuckMode() const OVERRIDE;
+ virtual const string& response_body() OVERRIDE;
+ virtual bool connected() const OVERRIDE;
+ // These functions are all unimplemented functions from SimpleClient, and log
+ // DFATAL if called by users of SimpleClient.
+ virtual ssize_t SendAndWaitForResponse(const void *buffer,
+ size_t size) OVERRIDE;
+ virtual void Bind(IPEndPoint* local_address) OVERRIDE;
+ virtual string SerializeMessage(const HTTPMessage& message) OVERRIDE;
+ virtual IPAddressNumber bind_to_address() const OVERRIDE;
+ virtual void set_bind_to_address(IPAddressNumber address) OVERRIDE;
+ virtual const IPEndPoint& address() const OVERRIDE;
+ virtual size_t requests_sent() const OVERRIDE;
// From QuicDataStream::Visitor
virtual void OnClose(QuicDataStream* stream) OVERRIDE;
// Configures client_ to take ownership of and use the writer.
// Must be called before initial connect.
- void UseWriter(net::test::QuicTestWriter* writer);
- // If the given GUID is nonzero, configures client_ to use a specific GUID
- // instead of a random one.
- void UseGuid(QuicGuid guid);
+ void UseWriter(QuicPacketWriterWrapper* writer);
+ // If the given ConnectionId is nonzero, configures client_ to use a specific
+ // ConnectionId instead of a random one.
+ void UseConnectionId(QuicConnectionId connection_id);
// Returns NULL if the maximum number of streams have already been created.
QuicSpdyClientStream* GetOrCreateStream();
QuicRstStreamErrorCode stream_error() { return stream_error_; }
- QuicErrorCode connection_error() { return client()->session()->error(); }
+ QuicErrorCode connection_error();
- QuicClient* client() { return client_.get(); }
+ MockableQuicClient* client();
// cert_common_name returns the common name value of the server's certificate,
// or the empty string if no certificate was presented.
const string& cert_common_name() const;
- const string& response_body() {return response_;}
- bool connected() const;
+ // Get the server config map.
+ QuicTagValueMap GetServerConfig() const;
void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
void set_priority(QuicPriority priority) { priority_ = priority; }
+ // Sets client's FEC policy. This policy applies to the data stream(s), and
+ // also to the headers and crypto streams.
+ void SetFecPolicy(FecPolicy fec_policy);
+
void WaitForWriteToFlush();
- private:
- void Initialize(IPEndPoint address, const string& hostname, bool secure);
+ EpollServer* epoll_server() { return &epoll_server_; }
+
+ protected:
+ QuicTestClient();
- IPEndPoint server_address_;
- IPEndPoint client_address_;
- scoped_ptr<QuicClient> client_; // The actual client
+ void Initialize(bool secure);
+
+ void set_client(MockableQuicClient* client) { client_.reset(client); }
+
+ private:
+ EpollServer epoll_server_;
+ scoped_ptr<MockableQuicClient> client_; // The actual client
QuicSpdyClientStream* stream_;
QuicRstStreamErrorCode stream_error_;
@@ -132,7 +189,7 @@ class QuicTestClient : public QuicDataStream::Visitor {
// The number of uncompressed HTTP header bytes received.
int response_header_size_;
// The number of HTTP body bytes received.
- int response_body_size_;
+ int64 response_body_size_;
// True if we tried to connect already since the last call to Disconnect().
bool connect_attempted_;
bool secure_;
@@ -142,10 +199,13 @@ class QuicTestClient : public QuicDataStream::Visitor {
bool auto_reconnect_;
// Should we buffer the response body? Defaults to true.
bool buffer_body_;
-
+ // FEC policy for data sent by this client.
+ FecPolicy fec_policy_;
// proof_verifier_ points to a RecordingProofVerifier that is owned by
// client_.
ProofVerifier* proof_verifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicTestClient);
};
} // namespace test
@@ -153,4 +213,4 @@ class QuicTestClient : public QuicDataStream::Visitor {
} // namespace tools
} // namespace net
-#endif // NET_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
diff --git a/chromium/net/tools/quic/test_tools/quic_test_utils.cc b/chromium/net/tools/quic/test_tools/quic_test_utils.cc
index 1aad3273832..d46eae5b734 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_utils.cc
@@ -4,47 +4,59 @@
#include "net/tools/quic/test_tools/quic_test_utils.h"
-#include "base/sha1.h"
#include "net/quic/quic_connection.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
using base::StringPiece;
+using net::test::MakeAckFrame;
using net::test::MockHelper;
+using net::test::QuicConnectionPeer;
namespace net {
namespace tools {
namespace test {
MockConnection::MockConnection(bool is_server)
- : QuicConnection(kTestGuid,
+ : QuicConnection(kTestConnectionId,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
MockConnection::MockConnection(IPEndPoint address,
bool is_server)
- : QuicConnection(kTestGuid, address,
+ : QuicConnection(kTestConnectionId, address,
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
-MockConnection::MockConnection(QuicGuid guid,
+MockConnection::MockConnection(QuicConnectionId connection_id,
bool is_server)
- : QuicConnection(guid,
+ : QuicConnection(connection_id,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
is_server, QuicSupportedVersions()),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ writer_(QuicConnectionPeer::GetWriter(this)),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server,
+ const QuicVersionVector& supported_versions)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(net::test::Loopback4(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ new testing::NiceMock<MockPacketWriter>(),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -55,18 +67,21 @@ void MockConnection::AdvanceTime(QuicTime::Delta delta) {
static_cast<MockHelper*>(helper())->AdvanceTime(delta);
}
-uint64 SimpleRandom::RandUint64() {
- unsigned char hash[base::kSHA1Length];
- base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
- hash);
- memcpy(&seed_, hash, sizeof(seed_));
- return seed_;
+QuicAckFrame MakeAckFrameWithNackRanges(
+ size_t num_nack_ranges, QuicPacketSequenceNumber least_unacked) {
+ QuicAckFrame ack = MakeAckFrame(2 * num_nack_ranges + least_unacked,
+ least_unacked);
+ // Add enough missing packets to get num_nack_ranges nack ranges.
+ for (QuicPacketSequenceNumber i = 1; i < 2 * num_nack_ranges; i += 2) {
+ ack.received_info.missing_packets.insert(least_unacked + i);
+ }
+ return ack;
}
TestSession::TestSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicSession(connection, config),
- crypto_stream_(NULL) {
+ : QuicSession(connection, config),
+ crypto_stream_(NULL) {
}
TestSession::~TestSession() {}
@@ -85,19 +100,10 @@ MockPacketWriter::MockPacketWriter() {
MockPacketWriter::~MockPacketWriter() {
}
-MockQuicSessionOwner::MockQuicSessionOwner() {
-}
-
-MockQuicSessionOwner::~MockQuicSessionOwner() {
-}
-
-bool TestDecompressorVisitor::OnDecompressedData(StringPiece data) {
- data.AppendToString(&data_);
- return true;
+MockQuicServerSessionVisitor::MockQuicServerSessionVisitor() {
}
-void TestDecompressorVisitor::OnDecompressionError() {
- error_ = true;
+MockQuicServerSessionVisitor::~MockQuicServerSessionVisitor() {
}
MockAckNotifierDelegate::MockAckNotifierDelegate() {
diff --git a/chromium/net/tools/quic/test_tools/quic_test_utils.h b/chromium/net/tools/quic/test_tools/quic_test_utils.h
index 986665bd1ed..a889a42ee0d 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_utils.h
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Common utilities for Quic tests
+
#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
@@ -11,7 +13,6 @@
#include "net/quic/quic_connection.h"
#include "net/quic/quic_packet_writer.h"
#include "net/quic/quic_session.h"
-#include "net/quic/quic_spdy_decompressor.h"
#include "net/spdy/spdy_framer.h"
#include "net/tools/quic/quic_server_session.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -24,38 +25,31 @@ class IPEndPoint;
namespace tools {
namespace test {
-static const QuicGuid kTestGuid = 42;
+static const QuicConnectionId kTestConnectionId = 42;
static const int kTestPort = 123;
+static const uint32 kInitialStreamFlowControlWindowForTest =
+ 32 * 1024; // 32 KB
+static const uint32 kInitialSessionFlowControlWindowForTest =
+ 64 * 1024; // 64 KB
-// Simple random number generator used to compute random numbers suitable
-// for pseudo-randomly dropping packets in tests. It works by computing
-// the sha1 hash of the current seed, and using the first 64 bits as
-// the next random number, and the next seed.
-class SimpleRandom {
- public:
- SimpleRandom() : seed_(0) {}
-
- // Returns a random number in the range [0, kuint64max].
- uint64 RandUint64();
-
- void set_seed(uint64 seed) { seed_ = seed; }
-
- private:
- uint64 seed_;
-};
+// Testing convenience method to construct a QuicAckFrame with |num_nack_ranges|
+// nack ranges of width 1 packet, starting from |least_unacked|.
+QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
+ QuicPacketSequenceNumber least_unacked);
class MockConnection : public QuicConnection {
public:
- // Uses a MockHelper, GUID of 42, and 127.0.0.1:123.
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
- // Uses a MockHelper, GUID of 42.
- MockConnection(IPEndPoint address,
- bool is_server);
+ // Uses a MockHelper, ConnectionId of 42.
+ MockConnection(IPEndPoint address, bool is_server);
// Uses a MockHelper, and 127.0.0.1:123
- MockConnection(QuicGuid guid,
- bool is_server);
+ MockConnection(QuicConnectionId connection_id, bool is_server);
+
+ // Uses a Mock helper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, const QuicVersionVector& supported_versions);
virtual ~MockConnection();
@@ -70,12 +64,19 @@ class MockConnection : public QuicConnection {
MOCK_METHOD2(SendConnectionCloseWithDetails, void(
QuicErrorCode error,
const std::string& details));
- MOCK_METHOD2(SendRstStream, void(QuicStreamId id,
- QuicRstStreamErrorCode error));
+ MOCK_METHOD2(SendConnectionClosePacket, void(QuicErrorCode error,
+ const std::string& details));
+ MOCK_METHOD3(SendRstStream, void(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written));
MOCK_METHOD3(SendGoAway, void(QuicErrorCode error,
QuicStreamId last_good_stream_id,
const std::string& reason));
- MOCK_METHOD0(OnCanWrite, bool());
+ MOCK_METHOD1(SendBlocked, void(QuicStreamId id));
+ MOCK_METHOD2(SendWindowUpdate, void(QuicStreamId id,
+ QuicStreamOffset byte_offset));
+ MOCK_METHOD0(OnCanWrite, void());
+ MOCK_CONST_METHOD0(HasPendingWrites, bool());
void ReallyProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
@@ -102,10 +103,11 @@ class TestSession : public QuicSession {
void SetCryptoStream(QuicCryptoStream* stream);
- virtual QuicCryptoStream* GetCryptoStream();
+ virtual QuicCryptoStream* GetCryptoStream() OVERRIDE;
private:
QuicCryptoStream* crypto_stream_;
+
DISALLOW_COPY_AND_ASSIGN(TestSession);
};
@@ -114,42 +116,46 @@ class MockPacketWriter : public QuicPacketWriter {
MockPacketWriter();
virtual ~MockPacketWriter();
- MOCK_METHOD5(WritePacket,
+ MOCK_METHOD4(WritePacket,
WriteResult(const char* buffer,
size_t buf_len,
const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer));
+ const IPEndPoint& peer_address));
MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool());
-};
+ MOCK_CONST_METHOD0(IsWriteBlocked, bool());
+ MOCK_METHOD0(SetWritable, void());
-class MockQuicSessionOwner : public QuicSessionOwner {
- public:
- MockQuicSessionOwner();
- ~MockQuicSessionOwner();
- MOCK_METHOD2(OnConnectionClosed, void(QuicGuid guid, QuicErrorCode error));
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockPacketWriter);
};
-class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
+class MockQuicServerSessionVisitor : public QuicServerSessionVisitor {
public:
- virtual ~TestDecompressorVisitor() {}
- virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
- virtual void OnDecompressionError() OVERRIDE;
-
- std::string data() { return data_; }
- bool error() { return error_; }
+ MockQuicServerSessionVisitor();
+ virtual ~MockQuicServerSessionVisitor();
+ MOCK_METHOD2(OnConnectionClosed, void(QuicConnectionId connection_id,
+ QuicErrorCode error));
+ MOCK_METHOD1(OnWriteBlocked, void(QuicBlockedWriterInterface* writer));
private:
- std::string data_;
- bool error_;
+ DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionVisitor);
};
class MockAckNotifierDelegate : public QuicAckNotifier::DelegateInterface {
public:
MockAckNotifierDelegate();
+
+ MOCK_METHOD5(OnAckNotification, void(int num_original_packets,
+ int num_original_bytes,
+ int num_retransmitted_packets,
+ int num_retransmitted_bytes,
+ QuicTime::Delta delta_largest_observed));
+
+ protected:
+ // Object is ref counted.
virtual ~MockAckNotifierDelegate();
- MOCK_METHOD0(OnAckNotification, void());
+ DISALLOW_COPY_AND_ASSIGN(MockAckNotifierDelegate);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/server_thread.cc b/chromium/net/tools/quic/test_tools/server_thread.cc
index a1bebc760d5..337cc64cd08 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.cc
+++ b/chromium/net/tools/quic/test_tools/server_thread.cc
@@ -10,57 +10,62 @@ namespace net {
namespace tools {
namespace test {
-ServerThread::ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
+ServerThread::ServerThread(QuicServer* server,
+ IPEndPoint address,
bool strike_register_no_startup_period)
: SimpleThread("server_thread"),
- listening_(true, false),
confirmed_(true, false),
pause_(true, false),
paused_(true, false),
resume_(true, false),
quit_(true, false),
- server_(config, supported_versions),
+ server_(server),
address_(address),
- port_(0) {
+ port_(0),
+ initialized_(false) {
if (strike_register_no_startup_period) {
- server_.SetStrikeRegisterNoStartupPeriod();
+ server_->SetStrikeRegisterNoStartupPeriod();
}
}
-ServerThread::~ServerThread() {
-}
+ServerThread::~ServerThread() {}
-void ServerThread::Run() {
- server_.Listen(address_);
+void ServerThread::Initialize() {
+ if (initialized_) {
+ return;
+ }
+
+ server_->Listen(address_);
port_lock_.Acquire();
- port_ = server_.port();
+ port_ = server_->port();
port_lock_.Release();
- listening_.Signal();
+ initialized_ = true;
+}
+
+void ServerThread::Run() {
+ if (!initialized_) {
+ Initialize();
+ }
+
while (!quit_.IsSignaled()) {
if (pause_.IsSignaled() && !resume_.IsSignaled()) {
paused_.Signal();
resume_.Wait();
}
- server_.WaitForEvents();
+ server_->WaitForEvents();
MaybeNotifyOfHandshakeConfirmation();
}
- server_.Shutdown();
+ server_->Shutdown();
}
int ServerThread::GetPort() {
port_lock_.Acquire();
int rc = port_;
port_lock_.Release();
- return rc;
-}
-
-void ServerThread::WaitForServerStartup() {
- listening_.Wait();
+ return rc;
}
void ServerThread::WaitForCryptoHandshakeConfirmed() {
diff --git a/chromium/net/tools/quic/test_tools/server_thread.h b/chromium/net/tools/quic/test_tools/server_thread.h
index ed36c37b349..6066d974d18 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.h
+++ b/chromium/net/tools/quic/test_tools/server_thread.h
@@ -17,18 +17,18 @@ namespace test {
// Simple wrapper class to run server in a thread.
class ServerThread : public base::SimpleThread {
public:
- ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
+ ServerThread(QuicServer* server,
+ IPEndPoint address,
bool strike_register_no_startup_period);
virtual ~ServerThread();
- // SimpleThread implementation.
- virtual void Run() OVERRIDE;
+ // Prepares the server, but does not start accepting connections. Useful for
+ // injecting mocks.
+ void Initialize();
- // Waits until the server has started and is listening for requests.
- void WaitForServerStartup();
+ // Runs the event loop. Will initialize if necessary.
+ virtual void Run() OVERRIDE;
// Waits for the handshake to be confirmed for the first session created.
void WaitForCryptoHandshakeConfirmed();
@@ -48,7 +48,7 @@ class ServerThread : public base::SimpleThread {
// Returns the underlying server. Care must be taken to avoid data races
// when accessing the server. It is always safe to access the server
// after calling Pause() and before calling Resume().
- QuicServer* server() { return &server_; }
+ QuicServer* server() { return server_.get(); }
// Returns the port that the server is listening on.
int GetPort();
@@ -56,7 +56,6 @@ class ServerThread : public base::SimpleThread {
private:
void MaybeNotifyOfHandshakeConfirmation();
- base::WaitableEvent listening_; // Notified when the server is listening.
base::WaitableEvent confirmed_; // Notified when the first handshake is
// confirmed.
base::WaitableEvent pause_; // Notified when the server should pause.
@@ -64,11 +63,13 @@ class ServerThread : public base::SimpleThread {
base::WaitableEvent resume_; // Notified when the server should resume.
base::WaitableEvent quit_; // Notified when the server should quit.
- tools::QuicServer server_;
+ scoped_ptr<QuicServer> server_;
IPEndPoint address_;
base::Lock port_lock_;
int port_;
+ bool initialized_;
+
DISALLOW_COPY_AND_ASSIGN(ServerThread);
};
diff --git a/chromium/net/tools/quic/test_tools/simple_client.cc b/chromium/net/tools/quic/test_tools/simple_client.cc
new file mode 100644
index 00000000000..46f5b9d6877
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/simple_client.cc
@@ -0,0 +1,36 @@
+// Copyright 2014 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 "net/tools/quic/test_tools/simple_client.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+void SimpleClient::WaitForResponse() {
+ WaitForResponseForMs(-1);
+}
+
+// Waits for some data or response from the server.
+void SimpleClient::WaitForInitialResponse() {
+ WaitForInitialResponseForMs(-1);
+}
+
+int SimpleClient::ResetSocket() {
+ LOG(FATAL) << "SimpleClient::ResetSocket is not implemented";
+ return 0;
+}
+
+int SimpleClient::HalfClose() {
+ LOG(FATAL) << "SimpleClient::HalfClose is not implemented";
+ return 0;
+}
+
+int SimpleClient::response_header_size() const { return 0; }
+
+int64 SimpleClient::response_body_size() const { return 0; }
+
+} // namespace net
+} // namespace tools
+} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/simple_client.h b/chromium/net/tools/quic/test_tools/simple_client.h
new file mode 100644
index 00000000000..9277fcbf18d
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/simple_client.h
@@ -0,0 +1,159 @@
+// Copyright 2014 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.
+
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "net/base/ip_endpoint.h"
+#include "net/tools/balsa/balsa_frame.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+class HTTPMessage;
+
+class SimpleClient {
+ public:
+ virtual ~SimpleClient() {}
+
+ // Clears any outstanding state and sends 'size' bytes from 'buffer' to the
+ // server, possibly with multiple send operations. Returns 'size' on success
+ // and -1 on error. Callers should assume that any return value other than
+ // 'size' indicates failure.
+ virtual ssize_t Send(const void *buffer, size_t size) = 0;
+
+ // Serialize and send an HTTP request.
+ virtual ssize_t SendMessage(const HTTPMessage& message) = 0;
+
+ // Clears any outstanding state, sends 'size' bytes from 'buffer' and waits
+ // for a response or an error.
+ virtual ssize_t SendAndWaitForResponse(const void *buffer, size_t size) = 0;
+
+ // Clears any outstanding state and sends a simple GET of 'uri' to the
+ // server.
+ virtual ssize_t SendRequest(const std::string& uri) = 0;
+
+ // The response body is returned as a string.
+ virtual std::string SendCustomSynchronousRequest(
+ const HTTPMessage& message) = 0;
+ virtual std::string SendSynchronousRequest(const std::string& url) = 0;
+
+ // Returns once a complete response or a connection close has been received
+ // from the server.
+ virtual void WaitForResponse();
+
+ // Waits for some data or response from the server.
+ virtual void WaitForInitialResponse();
+
+ // Returns once a complete response or a connection close has been received
+ // from the server, or once the timeout expires. -1 for no timeout.
+ virtual void WaitForResponseForMs(int timeout_ms) = 0;
+
+ // Waits for some data or response from the server, or once the timeout
+ // expires. -1 for no timeout.
+ virtual void WaitForInitialResponseForMs(int timeout_ms) = 0;
+
+ // Clears any outstanding state from the last request.
+ virtual void ClearPerRequestState() = 0;
+
+ // Closes and reopens the connection to the server.
+ virtual void ResetConnection() = 0;
+
+ // Closes the connection to the server.
+ virtual void Disconnect() = 0;
+
+ // Both will return 0 on success, -1 otherwise.
+ // Sends out RST packet to peer.
+ // TODO(yongfa): Probably should be an interface too. LOG(FATAL) here
+ // to prevent accidental invocation.
+ virtual int ResetSocket();
+
+ virtual int HalfClose();
+
+ // Connects to the server. This should be done implicitly by Send*
+ // functions, but can be done explicitly as well.
+ virtual void Connect() = 0;
+
+ // Bind to the specified address. If set_bind_to_address() is called, this
+ // is called automatically on connect, but can be done explicitly to make
+ // LocalIPEndPoint() meaningful before actually connecting.
+ // Sets *local_address to the actual address bound to, which can be different
+ // if the given address has port 0.
+ virtual void Bind(IPEndPoint* local_address) = 0;
+
+ // Returns the local socket address of the client fd. Call only when
+ // connected.
+ // To get the local IPAdress, use LocalSocketAddress().host().
+ // To get the local port, use LocalSocketAddress.port().
+ virtual IPEndPoint LocalSocketAddress() const = 0;
+
+ // Returns the serialized message that would be sent by any of the HTTPMessage
+ // functions above.
+ virtual std::string SerializeMessage(const HTTPMessage& message) = 0;
+
+ // Sets the IP address to bind to on future Connect()s in case Bind() is not
+ // called in advance. If it's set to uninitialized IPAddress, default loopback
+ // address will be used.
+ virtual IPAddressNumber bind_to_address() const = 0;
+ virtual void set_bind_to_address(IPAddressNumber address) = 0;
+
+ // Returns true if the headers have been processed and are available.
+ virtual bool response_headers_complete() const = 0;
+
+ // Returns the response headers, if a response was completely framed.
+ // Undefined behavior otherwise.
+ virtual const BalsaHeaders* response_headers() const = 0;
+
+ // Returns true iff response has been fully received.
+ virtual bool response_complete() const = 0;
+
+ // Returns the number of bytes read from the server during this request.
+ virtual int64 response_size() const = 0;
+
+ // Returns the number of header bytes received during this request, if
+ // meaningful for the protocol.
+ virtual int response_header_size() const;
+
+ // Returns the number of body bytes received during this request, if
+ // meaningful for the protocol.
+ virtual int64 response_body_size() const;
+
+ // Returns the response body, if there was one. If there was no response, or
+ // if buffer_body() is false, returns an empty string.
+ virtual const std::string& response_body() = 0;
+
+ // The address the client is connected to.
+ virtual const IPEndPoint& address() const = 0;
+
+ // Returns true if the client is connected, false otherwise.
+ virtual bool connected() const = 0;
+
+ // Returns true if the server has informed the client that it is
+ // in "lame duck" mode, indicating intent to shut down and
+ // requesting that no further connections be established.
+ virtual bool ServerInLameDuckMode() const = 0;
+
+ // Return the number of bytes read off the wire by this client.
+ virtual size_t bytes_read() const = 0;
+
+ // Returns the number of bytes written to the wire by this client.
+ virtual size_t bytes_written() const = 0;
+
+ // Return the number of requests sent.
+ virtual size_t requests_sent() const = 0;
+
+ // Instructs the client to populate response_body().
+ virtual bool buffer_body() const = 0;
+ virtual void set_buffer_body(bool buffer_body) = 0;
+};
+
+} // namespace test
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_SIMPLE_CLIENT_H_