Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
new file mode 100644
index 0000000..efc823d
--- /dev/null
+++ b/quic/core/quic_versions.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2012 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/third_party/quiche/src/quic/core/quic_versions.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_tag.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+namespace {
+
+// Constructs a version label from the 4 bytes such that the on-the-wire
+// order will be: d, c, b, a.
+QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) {
+ return MakeQuicTag(d, c, b, a);
+}
+
+} // namespace
+
+ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol,
+ QuicTransportVersion transport_version)
+ : handshake_protocol(handshake_protocol),
+ transport_version(transport_version) {
+ if (handshake_protocol == PROTOCOL_TLS1_3 &&
+ !FLAGS_quic_supports_tls_handshake) {
+ QUIC_BUG << "TLS use attempted when not enabled";
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) {
+ os << ParsedQuicVersionToString(version);
+ return os;
+}
+
+QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
+ char proto = 0;
+ switch (parsed_version.handshake_protocol) {
+ case PROTOCOL_QUIC_CRYPTO:
+ proto = 'Q';
+ break;
+ case PROTOCOL_TLS1_3:
+ proto = 'T';
+ break;
+ default:
+ QUIC_LOG(ERROR) << "Invalid HandshakeProtocol: "
+ << parsed_version.handshake_protocol;
+ return 0;
+ }
+ switch (parsed_version.transport_version) {
+ case QUIC_VERSION_39:
+ return MakeVersionLabel(proto, '0', '3', '9');
+ case QUIC_VERSION_43:
+ return MakeVersionLabel(proto, '0', '4', '3');
+ case QUIC_VERSION_44:
+ return MakeVersionLabel(proto, '0', '4', '4');
+ case QUIC_VERSION_46:
+ return MakeVersionLabel(proto, '0', '4', '6');
+ case QUIC_VERSION_47:
+ return MakeVersionLabel(proto, '0', '4', '7');
+ case QUIC_VERSION_99:
+ return MakeVersionLabel(proto, '0', '9', '9');
+ default:
+ // This shold be an ERROR because we should never attempt to convert an
+ // invalid QuicTransportVersion to be written to the wire.
+ QUIC_LOG(ERROR) << "Unsupported QuicTransportVersion: "
+ << parsed_version.transport_version;
+ return 0;
+ }
+}
+
+QuicVersionLabelVector CreateQuicVersionLabelVector(
+ const ParsedQuicVersionVector& versions) {
+ QuicVersionLabelVector out;
+ out.reserve(versions.size());
+ for (const auto& version : versions) {
+ out.push_back(CreateQuicVersionLabel(version));
+ }
+ return out;
+}
+
+ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label) {
+ std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO};
+ if (FLAGS_quic_supports_tls_handshake) {
+ protocols.push_back(PROTOCOL_TLS1_3);
+ }
+ for (QuicTransportVersion version : kSupportedTransportVersions) {
+ for (HandshakeProtocol handshake : protocols) {
+ if (version_label ==
+ CreateQuicVersionLabel(ParsedQuicVersion(handshake, version))) {
+ return ParsedQuicVersion(handshake, version);
+ }
+ }
+ }
+ // Reading from the client so this should not be considered an ERROR.
+ QUIC_DLOG(INFO) << "Unsupported QuicVersionLabel version: "
+ << QuicVersionLabelToString(version_label);
+ return UnsupportedQuicVersion();
+}
+
+QuicTransportVersionVector AllSupportedTransportVersions() {
+ QuicTransportVersionVector supported_versions;
+ for (QuicTransportVersion version : kSupportedTransportVersions) {
+ supported_versions.push_back(version);
+ }
+ return supported_versions;
+}
+
+ParsedQuicVersionVector AllSupportedVersions() {
+ ParsedQuicVersionVector supported_versions;
+ for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) {
+ if (protocol == PROTOCOL_TLS1_3 && !FLAGS_quic_supports_tls_handshake) {
+ continue;
+ }
+ for (QuicTransportVersion version : kSupportedTransportVersions) {
+ if (protocol == PROTOCOL_TLS1_3 && version < QUIC_VERSION_47) {
+ // The TLS handshake is only deployable if CRYPTO frames are also used,
+ // which are added in v47.
+ continue;
+ }
+ supported_versions.push_back(ParsedQuicVersion(protocol, version));
+ }
+ }
+ return supported_versions;
+}
+
+// TODO(nharper): Remove this function when it is no longer in use.
+QuicTransportVersionVector CurrentSupportedTransportVersions() {
+ return FilterSupportedTransportVersions(AllSupportedTransportVersions());
+}
+
+ParsedQuicVersionVector CurrentSupportedVersions() {
+ return FilterSupportedVersions(AllSupportedVersions());
+}
+
+// TODO(nharper): Remove this function when it is no longer in use.
+QuicTransportVersionVector FilterSupportedTransportVersions(
+ QuicTransportVersionVector versions) {
+ ParsedQuicVersionVector parsed_versions;
+ for (QuicTransportVersion version : versions) {
+ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+ }
+ ParsedQuicVersionVector filtered_parsed_versions =
+ FilterSupportedVersions(parsed_versions);
+ QuicTransportVersionVector filtered_versions;
+ for (ParsedQuicVersion version : filtered_parsed_versions) {
+ filtered_versions.push_back(version.transport_version);
+ }
+ return filtered_versions;
+}
+
+ParsedQuicVersionVector FilterSupportedVersions(
+ ParsedQuicVersionVector versions) {
+ ParsedQuicVersionVector filtered_versions;
+ filtered_versions.reserve(versions.size());
+ for (ParsedQuicVersion version : versions) {
+ if (version.transport_version == QUIC_VERSION_99) {
+ if (GetQuicReloadableFlag(quic_enable_version_99) &&
+ GetQuicReloadableFlag(quic_enable_version_47) &&
+ GetQuicReloadableFlag(quic_enable_version_46) &&
+ GetQuicReloadableFlag(quic_enable_version_44) &&
+ GetQuicReloadableFlag(quic_enable_version_43)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_47) {
+ if (GetQuicReloadableFlag(quic_enable_version_47) &&
+ GetQuicReloadableFlag(quic_enable_version_46) &&
+ GetQuicReloadableFlag(quic_enable_version_44) &&
+ GetQuicReloadableFlag(quic_enable_version_43)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_46) {
+ if (GetQuicReloadableFlag(quic_enable_version_46) &&
+ GetQuicReloadableFlag(quic_enable_version_44) &&
+ GetQuicReloadableFlag(quic_enable_version_43)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_44) {
+ if (GetQuicReloadableFlag(quic_enable_version_44) &&
+ GetQuicReloadableFlag(quic_enable_version_43)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_43) {
+ if (GetQuicReloadableFlag(quic_enable_version_43)) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version.transport_version == QUIC_VERSION_39) {
+ if (!GetQuicReloadableFlag(quic_disable_version_39)) {
+ filtered_versions.push_back(version);
+ }
+ } else {
+ filtered_versions.push_back(version);
+ }
+ }
+ return filtered_versions;
+}
+
+QuicTransportVersionVector VersionOfIndex(
+ const QuicTransportVersionVector& versions,
+ int index) {
+ QuicTransportVersionVector version;
+ int version_count = versions.size();
+ if (index >= 0 && index < version_count) {
+ version.push_back(versions[index]);
+ } else {
+ version.push_back(QUIC_VERSION_UNSUPPORTED);
+ }
+ return version;
+}
+
+ParsedQuicVersionVector ParsedVersionOfIndex(
+ const ParsedQuicVersionVector& versions,
+ int index) {
+ ParsedQuicVersionVector version;
+ int version_count = versions.size();
+ if (index >= 0 && index < version_count) {
+ version.push_back(versions[index]);
+ } else {
+ version.push_back(UnsupportedQuicVersion());
+ }
+ return version;
+}
+
+QuicTransportVersionVector ParsedVersionsToTransportVersions(
+ const ParsedQuicVersionVector& versions) {
+ QuicTransportVersionVector transport_versions;
+ transport_versions.resize(versions.size());
+ for (size_t i = 0; i < versions.size(); ++i) {
+ transport_versions[i] = versions[i].transport_version;
+ }
+ return transport_versions;
+}
+
+QuicVersionLabel QuicVersionToQuicVersionLabel(
+ QuicTransportVersion transport_version) {
+ return CreateQuicVersionLabel(
+ ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version));
+}
+
+QuicString QuicVersionLabelToString(QuicVersionLabel version_label) {
+ return QuicTagToString(QuicEndian::HostToNet32(version_label));
+}
+
+QuicString QuicVersionLabelVectorToString(
+ const QuicVersionLabelVector& version_labels,
+ const QuicString& separator,
+ size_t skip_after_nth_version) {
+ QuicString result;
+ for (size_t i = 0; i < version_labels.size(); ++i) {
+ if (i != 0) {
+ result.append(separator);
+ }
+
+ if (i > skip_after_nth_version) {
+ result.append("...");
+ break;
+ }
+ result.append(QuicVersionLabelToString(version_labels[i]));
+ }
+ return result;
+}
+
+QuicTransportVersion QuicVersionLabelToQuicVersion(
+ QuicVersionLabel version_label) {
+ return ParseQuicVersionLabel(version_label).transport_version;
+}
+
+HandshakeProtocol QuicVersionLabelToHandshakeProtocol(
+ QuicVersionLabel version_label) {
+ return ParseQuicVersionLabel(version_label).handshake_protocol;
+}
+
+#define RETURN_STRING_LITERAL(x) \
+ case x: \
+ return #x
+
+QuicString QuicVersionToString(QuicTransportVersion transport_version) {
+ switch (transport_version) {
+ RETURN_STRING_LITERAL(QUIC_VERSION_39);
+ RETURN_STRING_LITERAL(QUIC_VERSION_43);
+ RETURN_STRING_LITERAL(QUIC_VERSION_44);
+ RETURN_STRING_LITERAL(QUIC_VERSION_46);
+ RETURN_STRING_LITERAL(QUIC_VERSION_47);
+ RETURN_STRING_LITERAL(QUIC_VERSION_99);
+ default:
+ return "QUIC_VERSION_UNSUPPORTED";
+ }
+}
+
+QuicString ParsedQuicVersionToString(ParsedQuicVersion version) {
+ return QuicVersionLabelToString(CreateQuicVersionLabel(version));
+}
+
+QuicString QuicTransportVersionVectorToString(
+ const QuicTransportVersionVector& versions) {
+ QuicString result = "";
+ for (size_t i = 0; i < versions.size(); ++i) {
+ if (i != 0) {
+ result.append(",");
+ }
+ result.append(QuicVersionToString(versions[i]));
+ }
+ return result;
+}
+
+QuicString ParsedQuicVersionVectorToString(
+ const ParsedQuicVersionVector& versions,
+ const QuicString& separator,
+ size_t skip_after_nth_version) {
+ QuicString result;
+ for (size_t i = 0; i < versions.size(); ++i) {
+ if (i != 0) {
+ result.append(separator);
+ }
+ if (i > skip_after_nth_version) {
+ result.append("...");
+ break;
+ }
+ result.append(ParsedQuicVersionToString(versions[i]));
+ }
+ return result;
+}
+
+ParsedQuicVersion UnsupportedQuicVersion() {
+ return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
+}
+
+#undef RETURN_STRING_LITERAL // undef for jumbo builds
+} // namespace quic