Map QuicErrorCodes to proper IETF QUIC Close Connection information.
THis CL maps a QuicErrorCode to either an IETF QUIC Application Connection
Close or Transport Connection Close. In the latter case, the mapping also
produces the correct IETF QUIC TransportErrorCode to use.
gfe-relnote: N/A code exercised only for IETF QUIC.
PiperOrigin-RevId: 261741702
Change-Id: I1e928046b18c86ff0a7cbcf013e0d9219c27d2dd
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 0c33604..a577bf1 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2683,12 +2683,23 @@
!GetUpdatedAckFrame().ack_frame->packets.Empty()) {
SendAck();
}
- QuicConnectionCloseFrame* frame =
- new QuicConnectionCloseFrame(error, details);
- // If version99/IETF QUIC set the close type. Default close type is Google
- // QUIC.
+ QuicConnectionCloseFrame* frame;
if (VersionHasIetfQuicFrames(transport_version())) {
- frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(error);
+ if (mapping.is_transport_close_) {
+ // Maps to a transport close
+ // TODO(fkastenholz) need to change "0" to get the frame type currently
+ // being processed so that it can be inserted into the frame.
+ frame = new QuicConnectionCloseFrame(error, details,
+ mapping.transport_error_code_, 0);
+ } else {
+ // Maps to an application close.
+ frame = new QuicConnectionCloseFrame(error, details,
+ mapping.application_error_code_);
+ }
+ } else {
+ frame = new QuicConnectionCloseFrame(error, details);
}
packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame));
packet_generator_.FlushAllQueuedFrames();
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 773db66..39d2760 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1437,11 +1437,27 @@
header.packet_number = QuicPacketNumber(number);
- QuicConnectionCloseFrame qccf(QUIC_PEER_GOING_AWAY, "");
+ QuicErrorCode kQuicErrorCode = QUIC_PEER_GOING_AWAY;
+ // This QuicConnectionCloseFrame will default to being for a Google QUIC
+ // close. If doing IETF QUIC then set fields appropriately for CC/T or CC/A,
+ // depending on the mapping.
+ QuicConnectionCloseFrame qccf(kQuicErrorCode, "");
if (VersionHasIetfQuicFrames(peer_framer_.transport_version())) {
- // Default close-type is Google QUIC. If doing IETF QUIC then
- // set close type to be IETF CC/T.
- qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(kQuicErrorCode);
+ if (mapping.is_transport_close_) {
+ // Maps to a transport close
+ qccf.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ qccf.transport_error_code = mapping.transport_error_code_;
+ // TODO(fkastenholz) need to change "0" to get the frame type currently
+ // being processed so that it can be inserted into the frame.
+ qccf.transport_close_frame_type = 0;
+ } else {
+ // Maps to an application close.
+ qccf.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE;
+ qccf.application_error_code = mapping.application_error_code_;
+ }
+ qccf.extracted_error_code = kQuicErrorCode;
}
QuicFrames frames;
@@ -1556,7 +1572,32 @@
const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
writer_->connection_close_frames();
ASSERT_EQ(1u, connection_close_frames.size());
- EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ if (!VersionHasIetfQuicFrames(version().transport_version)) {
+ EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ EXPECT_EQ(GOOGLE_QUIC_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ return;
+ }
+
+ QuicErrorCodeToIetfMapping mapping =
+ QuicErrorCodeToTransportErrorCode(expected_code);
+
+ if (mapping.is_transport_close_) {
+ // This Google QUIC Error Code maps to a transport close,
+ EXPECT_EQ(IETF_QUIC_TRANSPORT_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ EXPECT_EQ(mapping.transport_error_code_,
+ connection_close_frames[0].transport_error_code);
+ // TODO(fkastenholz): when the extracted error code CL lands,
+ // need to test that extracted==expected.
+ } else {
+ // This maps to an application close.
+ EXPECT_EQ(expected_code, connection_close_frames[0].quic_error_code);
+ EXPECT_EQ(IETF_QUIC_APPLICATION_CONNECTION_CLOSE,
+ connection_close_frames[0].close_type);
+ // TODO(fkastenholz): when the extracted error code CL lands,
+ // need to test that extracted==expected.
+ }
}
QuicConnectionId connection_id_;
@@ -1597,6 +1638,36 @@
QuicConnectionTest,
::testing::ValuesIn(GetTestParams()));
+// These two tests ensure that the QuicErrorCode mapping works correctly.
+// Both tests expect to see a Google QUIC close if not running IETF QUIC.
+// If running IETF QUIC, the first will generate a transport connection
+// close, the second an application connection close.
+// The connection close codes for the two tests are manually chosen;
+// they are expected to always map to transport- and application-
+// closes, respectively. If that changes, mew codes should be chosen.
+TEST_P(QuicConnectionTest, CloseErrorCodeTestTransport) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(
+ IETF_QUIC_PROTOCOL_VIOLATION, "Should be transport close",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION);
+}
+
+// Test that the IETF QUIC Error code mapping function works
+// properly for application connection close codes.
+TEST_P(QuicConnectionTest, CloseErrorCodeTestApplication) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.CloseConnection(
+ QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE,
+ "Should be application close",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ EXPECT_FALSE(connection_.connected());
+ TestConnectionCloseQuicErrorCode(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE);
+}
+
TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1942,8 +2013,13 @@
TestConnectionCloseQuicErrorCode(QUIC_INTERNAL_ERROR);
const std::vector<QuicConnectionCloseFrame>& connection_close_frames =
writer_->connection_close_frames();
- EXPECT_EQ("Packet written out of order.",
- connection_close_frames[0].error_details);
+ if (VersionHasIetfQuicFrames(version().transport_version)) {
+ EXPECT_EQ("1:Packet written out of order.",
+ connection_close_frames[0].error_details);
+ } else {
+ EXPECT_EQ("Packet written out of order.",
+ connection_close_frames[0].error_details);
+ }
}
TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) {
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc
index 102b60e..38572f1 100644
--- a/quic/core/quic_types.cc
+++ b/quic/core/quic_types.cc
@@ -124,4 +124,309 @@
return os;
}
+QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode(
+ QuicErrorCode error) {
+ switch (error) {
+ // TODO(fkastenholz): Currently, all QuicError codes will map
+ // to application error codes and the original Google QUIC error
+ // code. This will change over time as we go through all calls to
+ // CloseConnection() and see whether the call is a Transport or an
+ // Application close and what the translated code should be.
+ case QUIC_NO_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_NO_ERROR)}};
+ case QUIC_INTERNAL_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_INTERNAL_ERROR)}};
+ case QUIC_STREAM_DATA_AFTER_TERMINATION:
+ return {true,
+ {static_cast<uint64_t>(QUIC_STREAM_DATA_AFTER_TERMINATION)}};
+ case QUIC_INVALID_PACKET_HEADER:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PACKET_HEADER)}};
+ case QUIC_INVALID_FRAME_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_FRAME_DATA)}};
+ case QUIC_MISSING_PAYLOAD:
+ return {true, {static_cast<uint64_t>(QUIC_MISSING_PAYLOAD)}};
+ case QUIC_INVALID_FEC_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_FEC_DATA)}};
+ case QUIC_INVALID_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_DATA)}};
+ case QUIC_OVERLAPPING_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_OVERLAPPING_STREAM_DATA)}};
+ case QUIC_UNENCRYPTED_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_STREAM_DATA)}};
+ case QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA)}};
+ case QUIC_MAYBE_CORRUPTED_MEMORY:
+ return {true, {static_cast<uint64_t>(QUIC_MAYBE_CORRUPTED_MEMORY)}};
+ case QUIC_UNENCRYPTED_FEC_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_UNENCRYPTED_FEC_DATA)}};
+ case QUIC_INVALID_RST_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_RST_STREAM_DATA)}};
+ case QUIC_INVALID_CONNECTION_CLOSE_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_CONNECTION_CLOSE_DATA)}};
+ case QUIC_INVALID_GOAWAY_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_GOAWAY_DATA)}};
+ case QUIC_INVALID_WINDOW_UPDATE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_WINDOW_UPDATE_DATA)}};
+ case QUIC_INVALID_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_BLOCKED_DATA)}};
+ case QUIC_INVALID_STOP_WAITING_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STOP_WAITING_DATA)}};
+ case QUIC_INVALID_PATH_CLOSE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CLOSE_DATA)}};
+ case QUIC_INVALID_ACK_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_ACK_DATA)}};
+ case QUIC_INVALID_MESSAGE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_MESSAGE_DATA)}};
+ case QUIC_INVALID_VERSION_NEGOTIATION_PACKET:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_VERSION_NEGOTIATION_PACKET)}};
+ case QUIC_INVALID_PUBLIC_RST_PACKET:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PUBLIC_RST_PACKET)}};
+ case QUIC_DECRYPTION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_DECRYPTION_FAILURE)}};
+ case QUIC_ENCRYPTION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_ENCRYPTION_FAILURE)}};
+ case QUIC_PACKET_TOO_LARGE:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_TOO_LARGE)}};
+ case QUIC_PEER_GOING_AWAY:
+ return {true, {static_cast<uint64_t>(QUIC_PEER_GOING_AWAY)}};
+ case QUIC_INVALID_STREAM_ID:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_ID)}};
+ case QUIC_INVALID_PRIORITY:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PRIORITY)}};
+ case QUIC_TOO_MANY_OPEN_STREAMS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_OPEN_STREAMS)}};
+ case QUIC_TOO_MANY_AVAILABLE_STREAMS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_AVAILABLE_STREAMS)}};
+ case QUIC_PUBLIC_RESET:
+ return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESET)}};
+ case QUIC_INVALID_VERSION:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_VERSION)}};
+ case QUIC_INVALID_HEADER_ID:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADER_ID)}};
+ case QUIC_INVALID_NEGOTIATED_VALUE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_NEGOTIATED_VALUE)}};
+ case QUIC_DECOMPRESSION_FAILURE:
+ return {true, {static_cast<uint64_t>(QUIC_DECOMPRESSION_FAILURE)}};
+ case QUIC_NETWORK_IDLE_TIMEOUT:
+ return {true, {static_cast<uint64_t>(QUIC_NETWORK_IDLE_TIMEOUT)}};
+ case QUIC_HANDSHAKE_TIMEOUT:
+ return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_TIMEOUT)}};
+ case QUIC_ERROR_MIGRATING_ADDRESS:
+ return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_ADDRESS)}};
+ case QUIC_ERROR_MIGRATING_PORT:
+ return {true, {static_cast<uint64_t>(QUIC_ERROR_MIGRATING_PORT)}};
+ case QUIC_PACKET_WRITE_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_WRITE_ERROR)}};
+ case QUIC_PACKET_READ_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_PACKET_READ_ERROR)}};
+ case QUIC_EMPTY_STREAM_FRAME_NO_FIN:
+ return {true, {static_cast<uint64_t>(QUIC_EMPTY_STREAM_FRAME_NO_FIN)}};
+ case QUIC_INVALID_HEADERS_STREAM_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_HEADERS_STREAM_DATA)}};
+ case QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE)}};
+ case QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)}};
+ case QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)}};
+ case QUIC_FLOW_CONTROL_INVALID_WINDOW:
+ return {true, {static_cast<uint64_t>(QUIC_FLOW_CONTROL_INVALID_WINDOW)}};
+ case QUIC_CONNECTION_IP_POOLED:
+ return {true, {static_cast<uint64_t>(QUIC_CONNECTION_IP_POOLED)}};
+ case QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS)}};
+ case QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS)}};
+ case QUIC_CONNECTION_CANCELLED:
+ return {true, {static_cast<uint64_t>(QUIC_CONNECTION_CANCELLED)}};
+ case QUIC_BAD_PACKET_LOSS_RATE:
+ return {true, {static_cast<uint64_t>(QUIC_BAD_PACKET_LOSS_RATE)}};
+ case QUIC_PUBLIC_RESETS_POST_HANDSHAKE:
+ return {true, {static_cast<uint64_t>(QUIC_PUBLIC_RESETS_POST_HANDSHAKE)}};
+ case QUIC_FAILED_TO_SERIALIZE_PACKET:
+ return {true, {static_cast<uint64_t>(QUIC_FAILED_TO_SERIALIZE_PACKET)}};
+ case QUIC_TOO_MANY_RTOS:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_RTOS)}};
+ case QUIC_HANDSHAKE_FAILED:
+ return {true, {static_cast<uint64_t>(QUIC_HANDSHAKE_FAILED)}};
+ case QUIC_CRYPTO_TAGS_OUT_OF_ORDER:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TAGS_OUT_OF_ORDER)}};
+ case QUIC_CRYPTO_TOO_MANY_ENTRIES:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_ENTRIES)}};
+ case QUIC_CRYPTO_INVALID_VALUE_LENGTH:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INVALID_VALUE_LENGTH)}};
+ case QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)}};
+ case QUIC_INVALID_CRYPTO_MESSAGE_TYPE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)}};
+ case QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER)}};
+ case QUIC_INVALID_CHANNEL_ID_SIGNATURE:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_CHANNEL_ID_SIGNATURE)}};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)}};
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP)}};
+ case QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND)}};
+ case QUIC_UNSUPPORTED_PROOF_DEMAND:
+ return {true, {static_cast<uint64_t>(QUIC_UNSUPPORTED_PROOF_DEMAND)}};
+ case QUIC_CRYPTO_INTERNAL_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_INTERNAL_ERROR)}};
+ case QUIC_CRYPTO_VERSION_NOT_SUPPORTED:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_VERSION_NOT_SUPPORTED)}};
+ case QUIC_CRYPTO_NO_SUPPORT:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_NO_SUPPORT)}};
+ case QUIC_CRYPTO_TOO_MANY_REJECTS:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_TOO_MANY_REJECTS)}};
+ case QUIC_PROOF_INVALID:
+ return {true, {static_cast<uint64_t>(QUIC_PROOF_INVALID)}};
+ case QUIC_CRYPTO_DUPLICATE_TAG:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_DUPLICATE_TAG)}};
+ case QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT)}};
+ case QUIC_CRYPTO_SERVER_CONFIG_EXPIRED:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED)}};
+ case QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED:
+ return {true,
+ {static_cast<uint64_t>(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED)}};
+ case QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO)}};
+ case QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE)}};
+ case QUIC_CRYPTO_CHLO_TOO_LARGE:
+ return {true, {static_cast<uint64_t>(QUIC_CRYPTO_CHLO_TOO_LARGE)}};
+ case QUIC_VERSION_NEGOTIATION_MISMATCH:
+ return {true, {static_cast<uint64_t>(QUIC_VERSION_NEGOTIATION_MISMATCH)}};
+ case QUIC_BAD_MULTIPATH_FLAG:
+ return {true, {static_cast<uint64_t>(QUIC_BAD_MULTIPATH_FLAG)}};
+ case QUIC_MULTIPATH_PATH_DOES_NOT_EXIST:
+ return {true,
+ {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST)}};
+ case QUIC_MULTIPATH_PATH_NOT_ACTIVE:
+ return {true, {static_cast<uint64_t>(QUIC_MULTIPATH_PATH_NOT_ACTIVE)}};
+ case QUIC_IP_ADDRESS_CHANGED:
+ return {true, {static_cast<uint64_t>(QUIC_IP_ADDRESS_CHANGED)}};
+ case QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS)}};
+ case QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES)}};
+ case QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK)}};
+ case QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM)}};
+ case QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG)}};
+ case QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR:
+ return {
+ true,
+ {static_cast<uint64_t>(QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR)}};
+ case QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED)}};
+ case QUIC_TOO_MANY_STREAM_DATA_INTERVALS:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_STREAM_DATA_INTERVALS)}};
+ case QUIC_STREAM_SEQUENCER_INVALID_STATE:
+ return {true,
+ {static_cast<uint64_t>(QUIC_STREAM_SEQUENCER_INVALID_STATE)}};
+ case QUIC_TOO_MANY_SESSIONS_ON_SERVER:
+ return {true, {static_cast<uint64_t>(QUIC_TOO_MANY_SESSIONS_ON_SERVER)}};
+ case QUIC_STREAM_LENGTH_OVERFLOW:
+ return {true, {static_cast<uint64_t>(QUIC_STREAM_LENGTH_OVERFLOW)}};
+ case QUIC_INVALID_MAX_DATA_FRAME_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_MAX_DATA_FRAME_DATA)}};
+ case QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_MAX_STREAM_DATA_FRAME_DATA)}};
+ case QUIC_MAX_STREAMS_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_DATA)}};
+ case QUIC_STREAMS_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_DATA)}};
+ case QUIC_INVALID_STREAM_BLOCKED_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_STREAM_BLOCKED_DATA)}};
+ case QUIC_INVALID_NEW_CONNECTION_ID_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_NEW_CONNECTION_ID_DATA)}};
+ case QUIC_INVALID_STOP_SENDING_FRAME_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_STOP_SENDING_FRAME_DATA)}};
+ case QUIC_INVALID_PATH_CHALLENGE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_CHALLENGE_DATA)}};
+ case QUIC_INVALID_PATH_RESPONSE_DATA:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_PATH_RESPONSE_DATA)}};
+ case IETF_QUIC_PROTOCOL_VIOLATION:
+ return {true, {static_cast<uint64_t>(IETF_QUIC_PROTOCOL_VIOLATION)}};
+ case QUIC_INVALID_NEW_TOKEN:
+ return {true, {static_cast<uint64_t>(QUIC_INVALID_NEW_TOKEN)}};
+ case QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_DATA_RECEIVED_ON_WRITE_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_TRY_TO_WRITE_DATA_ON_READ_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_INVALID_RETIRE_CONNECTION_ID_DATA:
+ return {true,
+ {static_cast<uint64_t>(QUIC_INVALID_RETIRE_CONNECTION_ID_DATA)}};
+ case QUIC_STREAMS_BLOCKED_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_STREAMS_BLOCKED_ERROR)}};
+ case QUIC_MAX_STREAMS_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_MAX_STREAMS_ERROR)}};
+ case QUIC_HTTP_DECODER_ERROR:
+ return {true, {static_cast<uint64_t>(QUIC_HTTP_DECODER_ERROR)}};
+ case QUIC_STALE_CONNECTION_CANCELLED:
+ return {true, {static_cast<uint64_t>(QUIC_STALE_CONNECTION_CANCELLED)}};
+ case QUIC_IETF_GQUIC_ERROR_MISSING:
+ return {true, {static_cast<uint64_t>(QUIC_IETF_GQUIC_ERROR_MISSING)}};
+ case QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM:
+ return {true,
+ {static_cast<uint64_t>(
+ QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM)}};
+ case QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES:
+ return {true,
+ {static_cast<uint64_t>(QUIC_TOO_MANY_BUFFERED_CONTROL_FRAMES)}};
+ case QUIC_LAST_ERROR:
+ return {false, {static_cast<uint64_t>(QUIC_LAST_ERROR)}};
+ }
+ // If it's an unknown code, indicate it's an application error code.
+ return {false, {NO_IETF_QUIC_ERROR}};
+}
+
} // namespace quic
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index c3f70e7..8a5434e 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -523,6 +523,21 @@
std::ostream& os,
const QuicIetfTransportErrorCodes& c);
+// Returns the mapping of the QuicErrorCode to an IETF TransportErrorCode. If
+// first element of the pair is false, it means that an IETF Application Close
+// should be done instead.
+
+struct QuicErrorCodeToIetfMapping {
+ bool is_transport_close_;
+ union {
+ uint64_t application_error_code_;
+ QuicIetfTransportErrorCodes transport_error_code_;
+ };
+};
+
+QUIC_EXPORT_PRIVATE QuicErrorCodeToIetfMapping
+QuicErrorCodeToTransportErrorCode(QuicErrorCode error);
+
// Please note, this value cannot used directly for packet serialization.
enum QuicLongHeaderType : uint8_t {
VERSION_NEGOTIATION,