summaryrefslogtreecommitdiffstats
path: root/net/tools/quic
diff options
context:
space:
mode:
authorjokulik <jokulik@chromium.org>2016-03-24 15:35:30 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-24 22:37:10 +0000
commitf2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a (patch)
treea075e02a5d98fce698e53b975674271b17673b3b /net/tools/quic
parentef26d8f77ba056704780199893f1ebaf518136de (diff)
downloadchromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.zip
chromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.tar.gz
chromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.tar.bz2
Landing Recent QUIC changes until 3/18/2016 23:30 UTC
relnote: Add a QUIC end to end test of huge post. The test code has been added but is currently disabled, due to net_unittest timeout issues. Merge internal change: 117596033 https://codereview.chromium.org/1830253002/ relnote: Do not read rejected packet number in PUBLIC RESET packet. Merge internal change: 117595846 https://codereview.chromium.org/1834683002/ relnote: Trailers are now parsed and stored in QuicSpdyStream. Moved the TrailersWithoutOffset test to the parent QuicSpdyStreamTest. Deleted the ReceiveTrailersBeforeHeaders test entirely as it doesn't test useful behavior: it calls OnTrailingHeadersComplete directly but this is only ever called from within QuicSpdyStream (and subclasses). Switch to the new WriteOrBufferBody method. Merge internal change: 117582133 https://codereview.chromium.org/1832513004/ relnote: Move QuicSpdyClientStream::SendBody to QuicSpdyStream::WriteBody. Merge internal change: 117577200 https://codereview.chromium.org/1830043004/ relnote: Make ShouldCreate{Incoming,Outgoing}DynamicStream abstract methods in QuicSpdySession. No behavior change. Merge internal change: 117574127 https://codereview.chromium.org/1828123003/ relnote: Correctly set cmsg space for timestamping. Additionally, guard against future cmsg overflows. Not flag protected. The previous calculation for the cmsg space was too small by 8B. Merge internal change: 117568981 https://codereview.chromium.org/1828953002/ relnote: Creating a basic QUIC packet dumper Adding newlines to any logged quic frames Merge internal change: 117543172 https://codereview.chromium.org/1834593002/ relnote: Rename StreamSequencerBuffer to QuicStreamSequencerBuffer to bring it in line with other classes in //gfe/quic. No behavior change. Merge internal change: 117487896 https://codereview.chromium.org/1831723002/ relnote: Rename QuicSpdyStream::response_trailers_ to received_trailers_. No behavior change. QuicSpdyStream is used by servers and clients, received trailers could be request trailers. Merge internal change: 117483696 https://codereview.chromium.org/1822763002/ relnote: Introduces a QUIC_OVERLAPPING_STREAM_DATA error code, sent when receiving a stream frame containing data that overlaps with buffered data. Renames QUIC_INVALID_STREAM_FRAME to QUIC_EMPTY_STREAM_FRAME_NO_FIN Dan pointed out that QUIC_INVALID_STREAM_DATA is also used in the framer, making debugging the sequencer specific errors harder. Also the description of QUIC_INVALID_STREAM_DATA is that "STREAM frame data is malformed." which I don't think is true here: it's not malformed, it's just overlapping. Merge internal change: 117452324 https://codereview.chromium.org/1830063002/ relnote: Close QUIC connection if any error occurs in QuicStreamSequencerBuffer::OnStreamData. Flag protected behind default enabled --flag_quic_consolidate_onstreamframe_errors Flag protecting out of paranoia: new behavior is that if ever hit the QUIC_INTERNAL_ERROR branch in OnStreamData then we will now close the connection, whereas we did not before. Additionally a stream frame containing data which overlaps with existing data will now result in QUIC_INVALID_STREAM_DATA being sent on close, instead of QUIC_INVALID_STREAM_FRAME. Merge internal change: 117446575 https://codereview.chromium.org/1830773002/ relnote: Use SO_TIMESTAMPING for received packet timestamps. Guarded by flag_quic_use_socket_timestamp. This corrects the RTT for extremely low RTT connections (i.e. RTT < EpollServer iteration duration). This manifests as a ~1.5Gbps improvement in egress at 100% GFE CPU in the ustreamer load test, which while not indicative of reality, does bring it closer to the TCP+SSL load test behavior. In practice, this really just manages to reduce the number of calls to EpollServer::Now(). This is part of a broader set of changes to enable PACKET_RX_RING and all of the capabilities it provides, notably PACKET_TIMESTAMPING. Additionally, in QuicPacketReader's plain recvmsg path, ensure the returned server IP is valid as is done in the recvmmsg path. Merge internal change: 117434383 https://codereview.chromium.org/1828863002/ relnote: Remove QuicStreamSequencerBufferInterface that only has a single implementation. No behavior change. Merge internal change: 117397110 https://codereview.chromium.org/1823803003/ relnote: Report no client nonce as INCHOATE_HELLO_FAILURE. Merge internal change: 117371001 https://codereview.chromium.org/1820383002/ relnote: Add and plumb QuicReceivedPacket in the packet reception path. Optionally use its timestamp, guarded by gfe2_restart_flag_quic_use_socket_timestamp. This is part of a broader set of changes to enable socket-level timestamping and to enable PACKET_RX_RING with all of the capabilities it provides. Merge internal change: 117362867 https://codereview.chromium.org/1821843003/ relnote: Add QUIC 32 in which FEC related fields are removed from private flags and revived packet list are removed from ACK frame. Merge internal change: 117278937 https://codereview.chromium.org/1817223002/ relnote: rename QuicSpdyClientStream::headers to response_headers Merge internal change: 117272106 https://codereview.chromium.org/1822763002/ R=rch@chromium.org BUG= Review URL: https://codereview.chromium.org/1832953002 Cr-Commit-Position: refs/heads/master@{#383171}
Diffstat (limited to 'net/tools/quic')
-rw-r--r--net/tools/quic/end_to_end_test.cc86
-rw-r--r--net/tools/quic/quic_client.cc19
-rw-r--r--net/tools/quic/quic_client.h2
-rw-r--r--net/tools/quic/quic_client_session.h11
-rw-r--r--net/tools/quic/quic_client_session_test.cc14
-rw-r--r--net/tools/quic/quic_dispatcher.cc2
-rw-r--r--net/tools/quic/quic_dispatcher.h6
-rw-r--r--net/tools/quic/quic_dispatcher_test.cc9
-rw-r--r--net/tools/quic/quic_packet_reader.cc61
-rw-r--r--net/tools/quic/quic_packet_reader.h12
-rw-r--r--net/tools/quic/quic_process_packet_interface.h2
-rw-r--r--net/tools/quic/quic_server.cc2
-rw-r--r--net/tools/quic/quic_server_session_base.h4
-rw-r--r--net/tools/quic/quic_server_test.cc7
-rw-r--r--net/tools/quic/quic_simple_client.cc5
-rw-r--r--net/tools/quic/quic_simple_client.h2
-rw-r--r--net/tools/quic/quic_simple_server.cc3
-rw-r--r--net/tools/quic/quic_simple_server_stream.cc4
-rw-r--r--net/tools/quic/quic_simple_server_stream.h2
-rw-r--r--net/tools/quic/quic_simple_server_test.cc7
-rw-r--r--net/tools/quic/quic_socket_utils.cc73
-rw-r--r--net/tools/quic/quic_socket_utils.h43
-rw-r--r--net/tools/quic/quic_spdy_client_stream.cc14
-rw-r--r--net/tools/quic/quic_spdy_client_stream.h11
-rw-r--r--net/tools/quic/quic_spdy_client_stream_test.cc6
-rw-r--r--net/tools/quic/quic_time_wait_list_manager_test.cc12
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc18
-rw-r--r--net/tools/quic/test_tools/quic_test_client.h2
28 files changed, 318 insertions, 121 deletions
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 923808b..38bb4c4 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -1003,7 +1003,7 @@ TEST_P(EndToEndTest, DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked) {
// 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);
+ stream->WriteOrBufferBody("hello", false, nullptr);
// The stream now attempts to write, fails because it is still connection
// level flow control blocked, and is added to the write blocked list.
@@ -1505,7 +1505,7 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
// Open a data stream to make sure the stream level flow control is updated.
QuicSpdyClientStream* stream = client_->GetOrCreateStream();
- stream->SendBody("hello", false);
+ stream->WriteOrBufferBody("hello", false, nullptr);
// Client should have the right values for server's receive window.
EXPECT_EQ(kServerStreamIFCW,
@@ -1972,6 +1972,55 @@ class StreamWithErrorFactory : public QuicTestServer::StreamFactory {
string response_body_;
};
+// A test server stream that drops all received body.
+class ServerStreamThatDropsBody : public QuicSimpleServerStream {
+ public:
+ ServerStreamThatDropsBody(QuicStreamId id, QuicSpdySession* session)
+ : QuicSimpleServerStream(id, session) {}
+
+ ~ServerStreamThatDropsBody() override {}
+
+ protected:
+ void OnDataAvailable() override {
+ while (HasBytesToRead()) {
+ struct iovec iov;
+ if (GetReadableRegions(&iov, 1) == 0) {
+ // No more data to read.
+ break;
+ }
+ DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " << id();
+ MarkConsumed(iov.iov_len);
+ }
+
+ if (!sequencer()->IsClosed()) {
+ sequencer()->SetUnblocked();
+ return;
+ }
+
+ // If the sequencer is closed, then all the body, including the fin, has
+ // been consumed.
+ OnFinRead();
+
+ if (write_side_closed() || fin_buffered()) {
+ return;
+ }
+
+ SendResponse();
+ }
+};
+
+class ServerStreamThatDropsBodyFactory : public QuicTestServer::StreamFactory {
+ public:
+ ServerStreamThatDropsBodyFactory() {}
+
+ ~ServerStreamThatDropsBodyFactory() override{};
+
+ QuicSimpleServerStream* CreateStream(QuicStreamId id,
+ QuicSpdySession* session) override {
+ return new ServerStreamThatDropsBody(id, session);
+ }
+};
+
TEST_P(EndToEndTest, EarlyResponseFinRecording) {
set_smaller_flow_control_receive_window();
@@ -2369,6 +2418,39 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
EXPECT_EQ(12u, client_->num_responses());
}
+// TODO(fayang): this test seems to cause net_unittests timeouts :|
+TEST_P(EndToEndTest, DISABLED_TestHugePost) {
+ // This test tests a huge post with body size greater than 4GB, making sure
+ // QUIC code does not broke for 32-bit builds.
+ ServerStreamThatDropsBodyFactory stream_factory;
+ SetSpdyStreamFactory(&stream_factory);
+ ASSERT_TRUE(Initialize());
+ // Set client's epoll server's time out to 0 to make this test be finished
+ // within a short time.
+ client_->epoll_server()->set_timeout_in_us(0);
+
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // To avoid storing the whole request body in memory, use a loop to repeatedly
+ // send body size of kSizeBytes until the whole request body size is reached.
+ const int kSizeBytes = 128 * 1024;
+ HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/foo");
+ // Request body size is 4G plus one more kSizeBytes.
+ int64_t request_body_size_bytes = pow(2, 32) + kSizeBytes;
+ request.AddHeader("content-length", IntToString(request_body_size_bytes));
+ request.set_has_complete_message(false);
+ string body;
+ test::GenerateBody(&body, kSizeBytes);
+
+ client_->SendMessage(request);
+ for (int i = 0; i < request_body_size_bytes / kSizeBytes; ++i) {
+ bool fin = (i == request_body_size_bytes - 1);
+ client_->SendData(string(body.data(), kSizeBytes), fin);
+ client_->client()->WaitForEvents();
+ }
+ VerifyCleanConnection(false);
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index b0815d3..07617bb 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -391,7 +391,8 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
bool more_to_read = true;
while (connected() && more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
- GetLatestFD(), QuicClient::GetLatestClientAddress().port(), this,
+ GetLatestFD(), QuicClient::GetLatestClientAddress().port(),
+ *helper()->GetClock(), this,
overflow_supported_ ? &packets_dropped_ : nullptr);
}
}
@@ -408,22 +409,22 @@ void QuicClient::OnClose(QuicSpdyStream* stream) {
DCHECK(stream != nullptr);
QuicSpdyClientStream* client_stream =
static_cast<QuicSpdyClientStream*>(stream);
- BalsaHeaders headers;
- SpdyBalsaUtils::SpdyHeadersToResponseHeaders(client_stream->headers(),
- &headers);
+ BalsaHeaders response_headers;
+ SpdyBalsaUtils::SpdyHeadersToResponseHeaders(
+ client_stream->response_headers(), &response_headers);
if (response_listener_.get() != nullptr) {
- response_listener_->OnCompleteResponse(stream->id(), headers,
+ response_listener_->OnCompleteResponse(stream->id(), response_headers,
client_stream->data());
}
// Store response headers and body.
if (store_response_) {
- latest_response_code_ = headers.parsed_response_code();
- headers.DumpHeadersToString(&latest_response_headers_);
+ latest_response_code_ = response_headers.parsed_response_code();
+ response_headers.DumpHeadersToString(&latest_response_headers_);
latest_response_body_ = client_stream->data();
latest_response_trailers_ =
- client_stream->response_trailers().DebugString();
+ client_stream->received_trailers().DebugString();
}
}
@@ -486,7 +487,7 @@ int QuicClient::GetLatestFD() const {
void QuicClient::ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet) {
+ const QuicReceivedPacket& packet) {
session()->connection()->ProcessUdpPacket(self_address, peer_address, packet);
}
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index ef6b711..1df8514 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -187,7 +187,7 @@ class QuicClient : public QuicClientBase,
// packet.
void ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet) override;
+ const QuicReceivedPacket& packet) override;
QuicClientPushPromiseIndex* push_promise_index() {
return &push_promise_index_;
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index 2cbf236..651469d 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -60,6 +60,11 @@ class QuicClientSession : public QuicClientSessionBase {
protected:
// QuicSession methods:
QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override;
+ // If an outgoing stream can be created, return true.
+ bool ShouldCreateOutgoingDynamicStream() override;
+
+ // If an incoming stream can be created, return true.
+ bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
// Create the crypto stream. Called by Initialize()
virtual QuicCryptoClientStreamBase* CreateQuicCryptoStream();
@@ -74,12 +79,6 @@ class QuicClientSession : public QuicClientSessionBase {
QuicCryptoClientConfig* crypto_config() { return crypto_config_; }
private:
- // If an outgoing stream can be created, return true.
- bool ShouldCreateOutgoingDynamicStream();
-
- // If an incoming stream can be created, return true.
- bool ShouldCreateIncomingDynamicStream(QuicStreamId id);
-
scoped_ptr<QuicCryptoClientStreamBase> crypto_stream_;
QuicServerId server_id_;
QuicCryptoClientConfig* crypto_config_;
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index f2aa9c0..2837ef4 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -248,14 +248,14 @@ TEST_P(QuicClientSessionTest, InvalidPacketReceived) {
EXPECT_CALL(*connection_, OnError(_)).Times(1);
// Verify that empty packets don't close the connection.
- QuicEncryptedPacket zero_length_packet(nullptr, 0, false);
+ QuicReceivedPacket zero_length_packet(nullptr, 0, QuicTime::Zero(), false);
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
session_->ProcessUdpPacket(client_address, server_address,
zero_length_packet);
// Verifiy that small, invalid packets don't close the connection.
char buf[2] = {0x00, 0x01};
- QuicEncryptedPacket valid_packet(buf, 2, false);
+ QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false);
// Close connection shouldn't be called.
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
session_->ProcessUdpPacket(client_address, server_address, valid_packet);
@@ -264,11 +264,13 @@ TEST_P(QuicClientSessionTest, InvalidPacketReceived) {
QuicConnectionId connection_id = session_->connection()->connection_id();
scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
connection_id, false, false, false, kDefaultPathId, 100, "data"));
+ scoped_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*packet, QuicTime::Zero()));
// Change the last byte of the encrypted data.
- *(const_cast<char*>(packet->data() + packet->length() - 1)) += 1;
+ *(const_cast<char*>(received->data() + received->length() - 1)) += 1;
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0);
EXPECT_CALL(*connection_, OnError(Truly(CheckForDecryptionError))).Times(1);
- session_->ProcessUdpPacket(client_address, server_address, *packet);
+ session_->ProcessUdpPacket(client_address, server_address, *received);
}
// A packet with invalid framing should cause a connection to be closed.
@@ -286,8 +288,10 @@ TEST_P(QuicClientSessionTest, InvalidFramedPacketReceived) {
scoped_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
connection_id, false, false, false, kDefaultPathId, 100, "data",
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, nullptr));
+ scoped_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*packet, QuicTime::Zero()));
EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(1);
- session_->ProcessUdpPacket(client_address, server_address, *packet);
+ session_->ProcessUdpPacket(client_address, server_address, *received);
}
TEST_P(QuicClientSessionTest, PushPromiseOnPromiseHeaders) {
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index f662ee3..1b145ef 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -74,7 +74,7 @@ void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- const QuicEncryptedPacket& packet) {
+ const QuicReceivedPacket& packet) {
current_server_address_ = server_address;
current_client_address_ = client_address;
current_packet_ = &packet;
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 6ba8f2b..5ff52ce 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -63,7 +63,7 @@ class QuicDispatcher : public QuicServerSessionVisitor,
// an existing session, or passing it to the time wait list.
void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- const QuicEncryptedPacket& packet) override;
+ const QuicReceivedPacket& packet) override;
// Called when the socket becomes writable to allow queued writes to happen.
void OnCanWrite() override;
@@ -182,7 +182,7 @@ class QuicDispatcher : public QuicServerSessionVisitor,
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 QuicReceivedPacket& current_packet() { return *current_packet_; }
const QuicConfig& config() const { return config_; }
@@ -257,7 +257,7 @@ class QuicDispatcher : public QuicServerSessionVisitor,
// Information about the packet currently being handled.
IPEndPoint current_client_address_;
IPEndPoint current_server_address_;
- const QuicEncryptedPacket* current_packet_;
+ const QuicReceivedPacket* current_packet_;
QuicConnectionId current_connection_id_;
QuicFramer framer_;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 67fb2d6..1172d1f 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -229,9 +229,12 @@ class QuicDispatcherTest : public ::testing::Test {
scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
connection_id, has_version_flag, false, false, 0, packet_number, data,
connection_id_length, packet_number_length, &versions));
+ scoped_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(*packet, helper_.GetClock()->Now()));
data_ = string(packet->data(), packet->length());
- dispatcher_.ProcessPacket(server_address_, client_address, *packet);
+ dispatcher_.ProcessPacket(server_address_, client_address,
+ *received_packet);
}
void ValidatePacket(const QuicEncryptedPacket& packet) {
@@ -353,6 +356,8 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
packet.nonce_proof = 132232;
scoped_ptr<QuicEncryptedPacket> encrypted(
QuicFramer::BuildPublicResetPacket(packet));
+ scoped_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now()));
EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET,
ConnectionCloseSource::FROM_PEER))
.Times(1)
@@ -364,7 +369,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
.WillOnce(
Invoke(reinterpret_cast<MockConnection*>(session1_->connection()),
&MockConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted);
+ dispatcher_.ProcessPacket(IPEndPoint(), client_address, *received);
EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
// Dispatcher forwards subsequent packets for this connection_id to the time
diff --git a/net/tools/quic/quic_packet_reader.cc b/net/tools/quic/quic_packet_reader.cc
index 3f5f8c8..beba973 100644
--- a/net/tools/quic/quic_packet_reader.cc
+++ b/net/tools/quic/quic_packet_reader.cc
@@ -53,7 +53,7 @@ void QuicPacketReader::Initialize() {
hdr->msg_iovlen = 1;
hdr->msg_control = packets_[i].cbuf;
- hdr->msg_controllen = kSpaceForOverflowAndIp;
+ hdr->msg_controllen = QuicSocketUtils::kSpaceForCmsg;
}
#endif
}
@@ -63,18 +63,22 @@ QuicPacketReader::~QuicPacketReader() {}
bool QuicPacketReader::ReadAndDispatchPackets(
int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
#if MMSG_MORE
- return ReadAndDispatchManyPackets(fd, port, processor, packets_dropped);
+ return ReadAndDispatchManyPackets(fd, port, clock, processor,
+ packets_dropped);
#else
- return ReadAndDispatchSinglePacket(fd, port, processor, packets_dropped);
+ return ReadAndDispatchSinglePacket(fd, port, clock, processor,
+ packets_dropped);
#endif
}
bool QuicPacketReader::ReadAndDispatchManyPackets(
int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
#if MMSG_MORE
@@ -84,7 +88,7 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
msghdr* hdr = &mmsg_hdr_[i].msg_hdr;
hdr->msg_namelen = sizeof(sockaddr_storage);
DCHECK_EQ(1, hdr->msg_iovlen);
- hdr->msg_controllen = kSpaceForOverflowAndIp;
+ hdr->msg_controllen = QuicSocketUtils::kSpaceForCmsg;
}
int packets_read =
@@ -94,22 +98,42 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
return false; // recvmmsg failed.
}
+ QuicTime fallback_timestamp = QuicTime::Zero();
for (int i = 0; i < packets_read; ++i) {
if (mmsg_hdr_[i].msg_len == 0) {
continue;
}
+ if (mmsg_hdr_[i].msg_hdr.msg_controllen >= QuicSocketUtils::kSpaceForCmsg) {
+ QUIC_BUG << "Incorrectly set control length: "
+ << mmsg_hdr_[i].msg_hdr.msg_controllen << ", expected "
+ << QuicSocketUtils::kSpaceForCmsg;
+ continue;
+ }
+
IPEndPoint client_address = IPEndPoint(packets_[i].raw_address);
- IPAddressNumber server_ip =
- QuicSocketUtils::GetAddressFromMsghdr(&mmsg_hdr_[i].msg_hdr);
+ IPAddressNumber server_ip;
+ QuicTime packet_timestamp = QuicTime::Zero();
+ QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
+ &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_timestamp);
if (!IsInitializedAddress(server_ip)) {
QUIC_BUG << "Unable to get server address.";
continue;
}
- QuicEncryptedPacket packet(
- reinterpret_cast<char*>(packets_[i].iov.iov_base), mmsg_hdr_[i].msg_len,
- false);
+ if (FLAGS_quic_use_socket_timestamp) {
+ if (packet_timestamp == QuicTime::Zero()) {
+ // This isn't particularly desirable, but not all platforms support
+ // socket timestamping.
+ if (fallback_timestamp == QuicTime::Zero()) {
+ fallback_timestamp = clock.Now();
+ }
+ packet_timestamp = fallback_timestamp;
+ }
+ }
+
+ QuicReceivedPacket packet(reinterpret_cast<char*>(packets_[i].iov.iov_base),
+ mmsg_hdr_[i].msg_len, packet_timestamp, false);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
}
@@ -131,20 +155,33 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
bool QuicPacketReader::ReadAndDispatchSinglePacket(
int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
char buf[kMaxPacketSize];
IPEndPoint client_address;
IPAddress server_ip;
- int bytes_read = QuicSocketUtils::ReadPacket(
- fd, buf, arraysize(buf), packets_dropped, &server_ip, &client_address);
+ QuicTime timestamp = QuicTime::Zero();
+ int bytes_read =
+ QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), packets_dropped,
+ &server_ip, &timestamp, &client_address);
if (bytes_read < 0) {
return false; // ReadPacket failed.
}
- QuicEncryptedPacket packet(buf, bytes_read, false);
+ if (server_ip.empty()) {
+ QUIC_BUG << "Unable to get server address.";
+ return false;
+ }
+ if (FLAGS_quic_use_socket_timestamp && timestamp == QuicTime::Zero()) {
+ // This isn't particularly desirable, but not all platforms support socket
+ // timestamping.
+ timestamp = clock.Now();
+ }
+
+ QuicReceivedPacket packet(buf, bytes_read, timestamp, false);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
diff --git a/net/tools/quic/quic_packet_reader.h b/net/tools/quic/quic_packet_reader.h
index 6ffe26b..b388406 100644
--- a/net/tools/quic/quic_packet_reader.h
+++ b/net/tools/quic/quic_packet_reader.h
@@ -11,8 +11,10 @@
#include <sys/socket.h>
#include "base/macros.h"
+#include "net/quic/quic_clock.h"
#include "net/quic/quic_protocol.h"
#include "net/tools/quic/quic_process_packet_interface.h"
+#include "net/tools/quic/quic_socket_utils.h"
#define MMSG_MORE 0
@@ -21,9 +23,6 @@ namespace net {
#if MMSG_MORE
// Read in larger batches to minimize recvmmsg overhead.
const int kNumPacketsPerReadMmsgCall = 16;
-// Allocate space for in6_pktinfo as it's larger than in_pktinfo
-const int kSpaceForOverflowAndIp =
- CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
#endif
namespace test {
@@ -43,8 +42,11 @@ class QuicPacketReader {
// packets available on the socket.
// Populates |packets_dropped| if it is non-null and the socket is configured
// to track dropped packets and some packets are read.
+ // If the socket has timestamping enabled, the per packet timestamps will be
+ // passed to the processor. Otherwise, |clock| will be used.
virtual bool ReadAndDispatchPackets(int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -55,12 +57,14 @@ class QuicPacketReader {
// Reads and dispatches many packets using recvmmsg.
bool ReadAndDispatchManyPackets(int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
// Reads and dispatches a single packet using recvmsg.
static bool ReadAndDispatchSinglePacket(int fd,
int port,
+ const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -78,7 +82,7 @@ class QuicPacketReader {
// call on the packets.
struct sockaddr_storage raw_address;
// cbuf is used for ancillary data from the kernel on recvmmsg.
- char cbuf[kSpaceForOverflowAndIp];
+ char cbuf[QuicSocketUtils::kSpaceForCmsg];
// buf is used for the data read from the kernel on recvmmsg.
char buf[kMaxPacketSize];
};
diff --git a/net/tools/quic/quic_process_packet_interface.h b/net/tools/quic/quic_process_packet_interface.h
index cc5924a..aa1035d 100644
--- a/net/tools/quic/quic_process_packet_interface.h
+++ b/net/tools/quic/quic_process_packet_interface.h
@@ -17,7 +17,7 @@ class ProcessPacketInterface {
virtual ~ProcessPacketInterface() {}
virtual void ProcessPacket(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- const QuicEncryptedPacket& packet) = 0;
+ const QuicReceivedPacket& packet) = 0;
};
} // namespace net
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 1c878f1..832c1b6 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -168,7 +168,7 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
bool more_to_read = true;
while (more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
- fd_, port_, dispatcher_.get(),
+ fd_, port_, QuicEpollClock(&epoll_server_), dispatcher_.get(),
overflow_supported_ ? &packets_dropped_ : nullptr);
}
}
diff --git a/net/tools/quic/quic_server_session_base.h b/net/tools/quic/quic_server_session_base.h
index a93fd9c..d14f02b 100644
--- a/net/tools/quic/quic_server_session_base.h
+++ b/net/tools/quic/quic_server_session_base.h
@@ -95,12 +95,12 @@ class QuicServerSessionBase : public QuicSpdySession {
// Return false when connection is closed or forward secure encryption hasn't
// established yet or number of server initiated streams already reaches the
// upper limit.
- virtual bool ShouldCreateOutgoingDynamicStream();
+ bool ShouldCreateOutgoingDynamicStream() override;
// If we should create an incoming stream, returns true. Otherwise
// does error handling, including communicating the error to the client and
// possibly closing the connection, and returns false.
- virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id);
+ bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc
index 1e55e23..d59bc70 100644
--- a/net/tools/quic/quic_server_test.cc
+++ b/net/tools/quic/quic_server_test.cc
@@ -32,7 +32,7 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1234));
}
- void DispatchPacket(const QuicEncryptedPacket& packet) {
+ void DispatchPacket(const QuicReceivedPacket& packet) {
IPEndPoint client_addr, server_addr;
dispatcher_.ProcessPacket(server_addr, client_addr, packet);
}
@@ -59,8 +59,9 @@ TEST_F(QuicServerDispatchPacketTest, DispatchPacket) {
0x00
};
// clang-format on
- QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
- arraysize(valid_packet), false);
+ QuicReceivedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
+ arraysize(valid_packet),
+ QuicTime::Zero(), false);
EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1);
DispatchPacket(encrypted_valid_packet);
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index b1dcf19..928481a 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -339,7 +339,8 @@ void QuicSimpleClient::OnClose(QuicSpdyStream* stream) {
QuicSpdyClientStream* client_stream =
static_cast<QuicSpdyClientStream*>(stream);
HttpResponseInfo response;
- SpdyHeadersToHttpResponse(client_stream->headers(), net::HTTP2, &response);
+ SpdyHeadersToHttpResponse(client_stream->response_headers(), net::HTTP2,
+ &response);
if (response_listener_.get() != nullptr) {
response_listener_->OnCompleteResponse(stream->id(), *response.headers,
client_stream->data());
@@ -388,7 +389,7 @@ void QuicSimpleClient::OnReadError(int result,
Disconnect();
}
-bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet,
+bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) {
session()->connection()->ProcessUdpPacket(local_address, peer_address,
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index 0ac0087..bcd0bda 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -130,7 +130,7 @@ class QuicSimpleClient : public QuicClientBase,
// QuicChromiumPacketReader::Visitor
void OnReadError(int result, const DatagramClientSocket* socket) override;
- bool OnPacket(const QuicEncryptedPacket& packet,
+ bool OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) override;
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc
index 9e89a50..7713986 100644
--- a/net/tools/quic/quic_simple_server.cc
+++ b/net/tools/quic/quic_simple_server.cc
@@ -202,7 +202,8 @@ void QuicSimpleServer::OnReadComplete(int result) {
return;
}
- QuicEncryptedPacket packet(read_buffer_->data(), result, false);
+ QuicReceivedPacket packet(read_buffer_->data(), result,
+ helper_->GetClock()->Now(), false);
dispatcher_->ProcessPacket(server_address_, client_address_, packet);
StartReading();
diff --git a/net/tools/quic/quic_simple_server_stream.cc b/net/tools/quic/quic_simple_server_stream.cc
index b715574..e0a3c2f 100644
--- a/net/tools/quic/quic_simple_server_stream.cc
+++ b/net/tools/quic/quic_simple_server_stream.cc
@@ -58,7 +58,7 @@ void QuicSimpleServerStream::OnDataAvailable() {
body_.append(static_cast<char*>(iov.iov_base), iov.iov_len);
if (content_length_ >= 0 &&
- static_cast<int>(body_.size()) > content_length_) {
+ body_.size() > static_cast<uint64_t>(content_length_)) {
DVLOG(1) << "Body size (" << body_.size() << ") > content length ("
<< content_length_ << ").";
SendErrorResponse();
@@ -86,7 +86,7 @@ void QuicSimpleServerStream::OnDataAvailable() {
}
if (content_length_ > 0 &&
- content_length_ != static_cast<int>(body_.size())) {
+ static_cast<uint64_t>(content_length_) != body_.size()) {
DVLOG(1) << "Content length (" << content_length_ << ") != body size ("
<< body_.size() << ").";
SendErrorResponse();
diff --git a/net/tools/quic/quic_simple_server_stream.h b/net/tools/quic/quic_simple_server_stream.h
index 90cb0dc..b88b847 100644
--- a/net/tools/quic/quic_simple_server_stream.h
+++ b/net/tools/quic/quic_simple_server_stream.h
@@ -73,7 +73,7 @@ class QuicSimpleServerStream : public QuicSpdyStream {
// The parsed headers received from the client.
SpdyHeaderBlock request_headers_;
- int content_length_;
+ int64_t content_length_;
std::string body_;
DISALLOW_COPY_AND_ASSIGN(QuicSimpleServerStream);
diff --git a/net/tools/quic/quic_simple_server_test.cc b/net/tools/quic/quic_simple_server_test.cc
index c63501c..3a7c54e 100644
--- a/net/tools/quic/quic_simple_server_test.cc
+++ b/net/tools/quic/quic_simple_server_test.cc
@@ -30,7 +30,7 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test {
dispatcher_.InitializeWithWriter(nullptr);
}
- void DispatchPacket(const QuicEncryptedPacket& packet) {
+ void DispatchPacket(const QuicReceivedPacket& packet) {
IPEndPoint client_addr, server_addr;
dispatcher_.ProcessPacket(server_addr, client_addr, packet);
}
@@ -51,8 +51,9 @@ TEST_F(QuicChromeServerDispatchPacketTest, DispatchPacket) {
0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
// private flags
0x00};
- QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
- arraysize(valid_packet), false);
+ QuicReceivedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
+ arraysize(valid_packet),
+ QuicTime::Zero(), false);
EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1);
DispatchPacket(encrypted_valid_packet);
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index 9c8cac7..1ef874c 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -5,6 +5,7 @@
#include "net/tools/quic/quic_socket_utils.h"
#include <errno.h>
+#include <linux/net_tstamp.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
@@ -12,6 +13,8 @@
#include <string>
#include "base/logging.h"
+#include "net/quic/quic_bug_tracker.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
#ifndef SO_RXQ_OVFL
@@ -21,28 +24,36 @@
namespace net {
// static
-IPAddress QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) {
+void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(struct msghdr* hdr,
+ IPAddress* address,
+ QuicTime* timestamp) {
if (hdr->msg_controllen > 0) {
for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
cmsg = CMSG_NXTHDR(hdr, cmsg)) {
const uint8_t* addr_data = nullptr;
int len = 0;
if (cmsg->cmsg_type == IPV6_PKTINFO) {
- in6_pktinfo* info = reinterpret_cast<in6_pktinfo*> CMSG_DATA(cmsg);
+ in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
addr_data = reinterpret_cast<const uint8_t*>(&info->ipi6_addr);
len = sizeof(in6_addr);
+ *address = IPAddress(addr_data, len);
} else if (cmsg->cmsg_type == IP_PKTINFO) {
- in_pktinfo* info = reinterpret_cast<in_pktinfo*> CMSG_DATA(cmsg);
+ in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
addr_data = reinterpret_cast<const uint8_t*>(&info->ipi_addr);
len = sizeof(in_addr);
- } else {
- continue;
+ *address = IPAddress(addr_data, len);
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SO_TIMESTAMPING) {
+ LinuxTimestamping* lts =
+ reinterpret_cast<LinuxTimestamping*>(CMSG_DATA(cmsg));
+ timespec* ts = &lts->systime;
+ int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) +
+ (static_cast<int64_t>(ts->tv_nsec) / 1000);
+ *timestamp =
+ QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(usec));
}
- return IPAddress(addr_data, len);
}
}
- DCHECK(false) << "Unable to get address from msghdr";
- return IPAddress();
}
// static
@@ -74,6 +85,13 @@ int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) {
}
// static
+int QuicSocketUtils::SetGetSoftwareReceiveTimestamp(int fd) {
+ int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
+ return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &timestamping,
+ sizeof(timestamping));
+}
+
+// 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";
@@ -97,11 +115,10 @@ int QuicSocketUtils::ReadPacket(int fd,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
+ QuicTime* timestamp,
IPEndPoint* peer_address) {
DCHECK(peer_address != nullptr);
- const int kSpaceForOverflowAndIp =
- CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo));
- char cbuf[kSpaceForOverflowAndIp];
+ char cbuf[kSpaceForCmsg];
memset(cbuf, 0, arraysize(cbuf));
iovec iov = {buffer, buf_len};
@@ -130,13 +147,28 @@ int QuicSocketUtils::ReadPacket(int fd,
return -1;
}
+ if (hdr.msg_controllen >= arraysize(cbuf)) {
+ QUIC_BUG << "Incorrectly set control length: " << hdr.msg_controllen
+ << ", expected " << arraysize(cbuf);
+ return -1;
+ }
+
if (dropped_packets != nullptr) {
GetOverflowFromMsghdr(&hdr, dropped_packets);
}
- if (self_address != nullptr) {
- *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr);
+
+ IPAddress stack_address;
+ if (self_address == nullptr) {
+ self_address = &stack_address;
+ }
+
+ QuicTime stack_timestamp = QuicTime::Zero();
+ if (timestamp == nullptr) {
+ timestamp = &stack_timestamp;
}
+ GetAddressAndTimestampFromMsghdr(&hdr, self_address, timestamp);
+
if (raw_address.ss_family == AF_INET) {
CHECK(peer_address->FromSockAddr(
reinterpret_cast<const sockaddr*>(&raw_address),
@@ -245,19 +277,28 @@ int QuicSocketUtils::CreateUDPSocket(const IPEndPoint& address,
*overflow_supported = true;
}
- if (!QuicSocketUtils::SetReceiveBufferSize(fd, kDefaultSocketReceiveBuffer)) {
+ if (!SetReceiveBufferSize(fd, kDefaultSocketReceiveBuffer)) {
return -1;
}
- if (!QuicSocketUtils::SetSendBufferSize(fd, kDefaultSocketReceiveBuffer)) {
+ if (!SetSendBufferSize(fd, kDefaultSocketReceiveBuffer)) {
return -1;
}
- rc = QuicSocketUtils::SetGetAddressInfo(fd, address_family);
+ rc = SetGetAddressInfo(fd, address_family);
if (rc < 0) {
LOG(ERROR) << "IP detection not supported" << strerror(errno);
return -1;
}
+
+ if (FLAGS_quic_use_socket_timestamp) {
+ rc = SetGetSoftwareReceiveTimestamp(fd);
+ if (rc < 0) {
+ LOG(WARNING) << "SO_TIMESTAMPING not supported; using fallback: "
+ << strerror(errno);
+ }
+ }
+
return fd;
}
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h
index a464089..72e90f8 100644
--- a/net/tools/quic/quic_socket_utils.h
+++ b/net/tools/quic/quic_socket_utils.h
@@ -7,6 +7,7 @@
#ifndef NET_TOOLS_QUIC_QUIC_SOCKET_UTILS_H_
#define NET_TOOLS_QUIC_QUIC_SOCKET_UTILS_H_
+#include <netinet/in.h>
#include <stddef.h>
#include <sys/socket.h>
@@ -20,11 +21,37 @@
namespace net {
+// This is the structure that SO_TIMESTAMPING fills into the cmsg header. It is
+// well-defined, but does not have a definition in a public header. See
+// https://www.kernel.org/doc/Documentation/networking/timestamping.txt for more
+// information.
+struct LinuxTimestamping {
+ // The converted system time of the timestamp.
+ struct timespec systime;
+ // Deprecated; serves only as padding.
+ struct timespec hwtimetrans;
+ // The raw hardware timestamp.
+ struct timespec hwtimeraw;
+};
+
class QuicSocketUtils {
public:
- // If the msghdr contains IP_PKTINFO or IPV6_PKTINFO, this will return the
- // IPAddress in that header. Returns an empty IPAddress on failure.
- static IPAddress GetAddressFromMsghdr(struct msghdr* hdr);
+ // The first integer is for overflow. The in6_pktinfo is the larger of the
+ // address structures present. LinuxTimestamping is present for socket
+ // timestamping.
+ // The final int is a sentinel so the msg_controllen feedback
+ // can be used to detect larger control messages than there is space for.
+ static const int kSpaceForCmsg =
+ CMSG_SPACE(CMSG_LEN(sizeof(int)) + CMSG_LEN(sizeof(in6_pktinfo)) +
+ CMSG_LEN(sizeof(LinuxTimestamping)) +
+ CMSG_LEN(sizeof(int)));
+
+ // Fills in |address| if |hdr| contains IP_PKTINFO or IPV6_PKTINFO. Fills in
+ // |timestamp| if |hdr| contains |SO_TIMESTAMPING|. |address| and |timestamp|
+ // must not be null.
+ static void GetAddressAndTimestampFromMsghdr(struct msghdr* hdr,
+ IPAddress* address,
+ QuicTime* timestamp);
// 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.
@@ -35,6 +62,10 @@ class QuicSocketUtils {
// address_family. Returns the return code from setsockopt.
static int SetGetAddressInfo(int fd, int address_family);
+ // Sets SO_TIMESTAMPING on the socket for software receive timestamping.
+ // Returns the return code from setsockopt.
+ static int SetGetSoftwareReceiveTimestamp(int fd);
+
// Sets the send buffer size to |size| and returns false if it fails.
static bool SetSendBufferSize(int fd, size_t size);
@@ -50,11 +81,17 @@ 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.
+ //
+ // If timestamp is non-null, it will be filled with the timestamp of the
+ // received packet, assuming a packet was read and the platform supports
+ // packet receipt timestamping. If the platform does not support packet
+ // receipt timestamping, timestamp will not be changed.
static int ReadPacket(int fd,
char* buffer,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
+ QuicTime* timestamp,
IPEndPoint* peer_address);
// Writes buf_len to the socket. If writing is successful, sets the result's
diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc
index af9ad0b..0274ee7 100644
--- a/net/tools/quic/quic_spdy_client_stream.cc
+++ b/net/tools/quic/quic_spdy_client_stream.cc
@@ -79,7 +79,7 @@ void QuicSpdyClientStream::OnTrailingHeadersComplete(bool fin,
void QuicSpdyClientStream::OnPromiseHeadersComplete(QuicStreamId promised_id,
size_t frame_len) {
header_bytes_read_ += frame_len;
- int content_length = -1;
+ int64_t content_length = -1;
SpdyHeaderBlock promise_headers;
if (!SpdyUtils::ParseHeaders(decompressed_headers().data(),
decompressed_headers().length(), &content_length,
@@ -111,7 +111,7 @@ void QuicSpdyClientStream::OnDataAvailable() {
data_.append(static_cast<char*>(iov.iov_base), iov.iov_len);
if (content_length_ >= 0 &&
- static_cast<int>(data_.size()) > content_length_) {
+ data_.size() > static_cast<uint64_t>(content_length_)) {
Reset(QUIC_BAD_APPLICATION_PAYLOAD);
return;
}
@@ -139,14 +139,4 @@ size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers,
return bytes_sent;
}
-void QuicSpdyClientStream::SendBody(const string& data, bool fin) {
- SendBody(data, fin, nullptr);
-}
-
-void QuicSpdyClientStream::SendBody(const string& data,
- bool fin,
- QuicAckListenerInterface* listener) {
- WriteOrBufferData(data, fin, listener);
-}
-
} // namespace net
diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h
index dcb8896..f225717 100644
--- a/net/tools/quic/quic_spdy_client_stream.h
+++ b/net/tools/quic/quic_spdy_client_stream.h
@@ -51,18 +51,11 @@ class QuicSpdyClientStream : public QuicSpdyStream {
base::StringPiece body,
bool fin);
- // Sends body data to the server, or buffers if it can't be sent immediately.
- void SendBody(const std::string& data, bool fin);
- // As above, but |delegate| will be notified once |data| is ACKed.
- void SendBody(const std::string& data,
- bool fin,
- QuicAckListenerInterface* listener);
-
// Returns the response data.
const std::string& data() { return data_; }
// Returns whatever headers have been received for this stream.
- const SpdyHeaderBlock& headers() { return response_headers_; }
+ const SpdyHeaderBlock& response_headers() { return response_headers_; }
size_t header_bytes_read() const { return header_bytes_read_; }
@@ -87,7 +80,7 @@ class QuicSpdyClientStream : public QuicSpdyStream {
SpdyHeaderBlock response_headers_;
// The parsed content-length, or -1 if none is specified.
- int content_length_;
+ int64_t content_length_;
int response_code_;
std::string data_;
size_t header_bytes_read_;
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index 8b42df5..85452bf 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -100,7 +100,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFraming) {
stream_->OnStreamHeadersComplete(false, headers_string_.size());
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
- EXPECT_EQ("200", stream_->headers().find(":status")->second);
+ EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
EXPECT_EQ(200, stream_->response_code());
EXPECT_EQ(body_, stream_->data());
}
@@ -110,7 +110,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) {
stream_->OnStreamHeadersComplete(false, headers_string_.size());
stream_->OnStreamFrame(
QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_));
- EXPECT_EQ("200", stream_->headers().find(":status")->second);
+ EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
EXPECT_EQ(200, stream_->response_code());
EXPECT_EQ(body_, stream_->data());
}
@@ -122,7 +122,7 @@ TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) {
stream_->OnStreamHeadersComplete(false, headers_string_.size());
// The headers should parse successfully.
EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
- EXPECT_EQ("200", stream_->headers().find(":status")->second);
+ EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
EXPECT_EQ(200, stream_->response_code());
EXPECT_CALL(*connection_,
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 12cb7fb..0ddfb4f 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -278,8 +278,7 @@ TEST_F(QuicTimeWaitListManagerTest, SendPublicReset) {
const int kRandomSequenceNumber = 1;
EXPECT_CALL(writer_,
WritePacket(_, _, server_address_.address(), client_address_, _))
- .With(Args<0, 1>(
- PublicResetPacketEq(connection_id_, kRandomSequenceNumber)))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id_, 0)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
ProcessPacket(connection_id_, kRandomSequenceNumber);
@@ -380,14 +379,14 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) {
// Let first write through.
EXPECT_CALL(writer_,
WritePacket(_, _, server_address_.address(), client_address_, _))
- .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number)))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
ProcessPacket(connection_id, packet_number);
// write block for the next packet.
EXPECT_CALL(writer_,
WritePacket(_, _, server_address_.address(), client_address_, _))
- .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number)))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0)))
.WillOnce(DoAll(Assign(&writer_is_blocked_, true),
Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN))));
EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_));
@@ -412,12 +411,11 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) {
writer_is_blocked_ = false;
EXPECT_CALL(writer_,
WritePacket(_, _, server_address_.address(), client_address_, _))
- .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number)))
+ .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length())));
EXPECT_CALL(writer_,
WritePacket(_, _, server_address_.address(), client_address_, _))
- .With(Args<0, 1>(
- PublicResetPacketEq(other_connection_id, other_packet_number)))
+ .With(Args<0, 1>(PublicResetPacketEq(other_connection_id, 0)))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, other_packet->length())));
time_wait_list_manager_.OnCanWrite();
}
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 7ce3621..97625d8 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -278,7 +278,7 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
ret = stream->SendRequest(spdy_headers, body, fin);
++num_requests_;
} else {
- stream->SendBody(body.as_string(), fin, delegate);
+ stream->WriteOrBufferBody(body.as_string(), fin, delegate);
ret = body.length();
}
if (FLAGS_enable_quic_stateless_reject_support) {
@@ -463,7 +463,7 @@ void QuicTestClient::ClearPerRequestState() {
response_ = "";
response_complete_ = false;
response_headers_complete_ = false;
- headers_.Clear();
+ response_headers_.Clear();
bytes_read_ = 0;
bytes_written_ = 0;
response_header_size_ = 0;
@@ -531,10 +531,11 @@ bool QuicTestClient::response_headers_complete() const {
const BalsaHeaders* QuicTestClient::response_headers() const {
if (stream_ != nullptr) {
- SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_);
- return &headers_;
+ SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->response_headers(),
+ &response_headers_);
+ return &response_headers_;
} else {
- return &headers_;
+ return &response_headers_;
}
}
@@ -569,13 +570,14 @@ void QuicTestClient::OnClose(QuicSpdyStream* stream) {
}
response_complete_ = true;
response_headers_complete_ = stream_->headers_decompressed();
- SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_);
- response_trailers_ = stream_->response_trailers();
+ SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->response_headers(),
+ &response_headers_);
+ response_trailers_ = stream_->received_trailers();
stream_error_ = stream_->stream_error();
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_header_size_ = response_headers_.GetSizeForWriteBuffer();
response_body_size_ = stream_->data().size();
stream_ = nullptr;
++num_responses_;
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 93cc385..b8530f4 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -240,7 +240,7 @@ class QuicTestClient : public test::SimpleClient,
bool response_complete_;
bool response_headers_complete_;
- mutable BalsaHeaders headers_;
+ mutable BalsaHeaders response_headers_;
// Parsed response trailers (if present), copied from the stream in OnClose.
SpdyHeaderBlock response_trailers_;