Verify receipt of connection_close in quic_client_interop
This CL also changes QuicFramer::MaybeExtractQuicErrorCode to map NO_IETF_QUIC_ERROR to QUIC_NO_ERROR.
gfe-relnote: change mapping of NO_IETF_QUIC_ERROR, not flag-protected
PiperOrigin-RevId: 274704993
Change-Id: If3e7f98dd6a2435a477ee318b44fce78e6ab6e30
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index a759adb..2d4d4a5 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -6603,7 +6603,12 @@
uint64_t extracted_error_code;
if (ed.size() < 2 || !QuicTextUtils::IsAllDigits(ed[0]) ||
!QuicTextUtils::StringToUint64(ed[0], &extracted_error_code)) {
- frame->extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ if (frame->close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE &&
+ frame->transport_error_code == NO_IETF_QUIC_ERROR) {
+ frame->extracted_error_code = QUIC_NO_ERROR;
+ } else {
+ frame->extracted_error_code = QUIC_IETF_GQUIC_ERROR_MISSING;
+ }
return;
}
// Return the error code (numeric) and the error details string without the
diff --git a/quic/test_tools/quic_connection_peer.cc b/quic/test_tools/quic_connection_peer.cc
index 8b99730..02775ca 100644
--- a/quic/test_tools/quic_connection_peer.cc
+++ b/quic/test_tools/quic_connection_peer.cc
@@ -357,5 +357,12 @@
connection->address_validated_ = true;
}
+// static
+void QuicConnectionPeer::SendConnectionClosePacket(QuicConnection* connection,
+ QuicErrorCode error,
+ const std::string& details) {
+ connection->SendConnectionClosePacket(error, details);
+}
+
} // namespace test
} // namespace quic
diff --git a/quic/test_tools/quic_connection_peer.h b/quic/test_tools/quic_connection_peer.h
index 5b97ae6..c5c972f 100644
--- a/quic/test_tools/quic_connection_peer.h
+++ b/quic/test_tools/quic_connection_peer.h
@@ -139,6 +139,10 @@
PacketHeaderFormat format);
static void AddBytesReceived(QuicConnection* connection, size_t length);
static void SetAddressValidated(QuicConnection* connection);
+
+ static void SendConnectionClosePacket(QuicConnection* connection,
+ QuicErrorCode error,
+ const std::string& details);
};
} // namespace test
diff --git a/quic/tools/quic_client_interop_test_bin.cc b/quic/tools/quic_client_interop_test_bin.cc
index 20a4699..2511141 100644
--- a/quic/tools/quic_client_interop_test_bin.cc
+++ b/quic/tools/quic_client_interop_test_bin.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
+#include "net/quic/platform/impl/quic_epoll_clock.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
#include "net/third_party/quiche/src/quic/tools/quic_client.h"
@@ -34,10 +35,10 @@
kStreamData,
// The connection close procedcure completes with a zero error code.
kConnectionClose,
- // An H3 transaction succeeded.
- kHttp3,
// A RETRY packet was successfully processed.
kRetry,
+ // An H3 transaction succeeded.
+ kHttp3,
};
char MatrixLetter(Feature f) {
@@ -64,6 +65,7 @@
std::set<Feature> features;
auto proof_verifier = std::make_unique<FakeProofVerifier>();
QuicEpollServer epoll_server;
+ QuicEpollClock epoll_clock(&epoll_server);
auto client = std::make_unique<QuicClient>(
addr, server_id, versions, &epoll_server, std::move(proof_verifier));
if (!client->Initialize()) {
@@ -95,9 +97,13 @@
client->set_store_response(true);
client->SendRequest(header_block, "", /*fin=*/true);
- // TODO(nharper): After some period of time, time out and don't report
- // success.
+ const QuicTime request_start_time = epoll_clock.Now();
+ static const auto request_timeout = QuicTime::Delta::FromSeconds(20);
while (client->WaitForEvents()) {
+ if (epoll_clock.Now() - request_start_time >= request_timeout) {
+ QUIC_LOG(ERROR) << "Timed out waiting for HTTP response";
+ return features;
+ }
}
QuicConnection* connection = client->session()->connection();
@@ -125,9 +131,28 @@
features.insert(Feature::kHttp3);
}
- // TODO(nharper): Check that we sent/received (which one?) a CONNECTION_CLOSE
- // with error code 0.
- features.insert(Feature::kConnectionClose);
+ if (connection != nullptr && connection->connected()) {
+ test::QuicConnectionPeer::SendConnectionClosePacket(
+ connection, QUIC_NO_ERROR, "Graceful close");
+ const QuicTime close_start_time = epoll_clock.Now();
+ static const auto close_timeout = QuicTime::Delta::FromSeconds(10);
+ while (client->connected()) {
+ client->epoll_network_helper()->RunEventLoop();
+ if (epoll_clock.Now() - close_start_time >= close_timeout) {
+ QUIC_LOG(ERROR) << "Timed out waiting for connection close";
+ return features;
+ }
+ }
+ const QuicErrorCode received_error = client->session()->error();
+ if (received_error == QUIC_NO_ERROR ||
+ received_error == QUIC_PUBLIC_RESET) {
+ features.insert(Feature::kConnectionClose);
+ } else {
+ QUIC_LOG(ERROR) << "Received error " << client->session()->error() << " "
+ << client->session()->error_details();
+ }
+ }
+
return features;
}