summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/transport
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/api/transport')
-rw-r--r--third_party/libwebrtc/api/transport/BUILD.gn167
-rw-r--r--third_party/libwebrtc/api/transport/DEPS7
-rw-r--r--third_party/libwebrtc/api/transport/OWNERS2
-rw-r--r--third_party/libwebrtc/api/transport/bitrate_settings.cc19
-rw-r--r--third_party/libwebrtc/api/transport/bitrate_settings.h50
-rw-r--r--third_party/libwebrtc/api/transport/bitrate_settings_gn/moz.build217
-rw-r--r--third_party/libwebrtc/api/transport/data_channel_transport_interface.h125
-rw-r--r--third_party/libwebrtc/api/transport/datagram_transport_interface_gn/moz.build209
-rw-r--r--third_party/libwebrtc/api/transport/enums.h49
-rw-r--r--third_party/libwebrtc/api/transport/field_trial_based_config.cc18
-rw-r--r--third_party/libwebrtc/api/transport/field_trial_based_config.h26
-rw-r--r--third_party/libwebrtc/api/transport/field_trial_based_config_gn/moz.build225
-rw-r--r--third_party/libwebrtc/api/transport/goog_cc_factory.cc65
-rw-r--r--third_party/libwebrtc/api/transport/goog_cc_factory.h61
-rw-r--r--third_party/libwebrtc/api/transport/goog_cc_gn/moz.build232
-rw-r--r--third_party/libwebrtc/api/transport/network_control.h140
-rw-r--r--third_party/libwebrtc/api/transport/network_control_gn/moz.build225
-rw-r--r--third_party/libwebrtc/api/transport/network_types.cc106
-rw-r--r--third_party/libwebrtc/api/transport/network_types.h278
-rw-r--r--third_party/libwebrtc/api/transport/rtp/BUILD.gn37
-rw-r--r--third_party/libwebrtc/api/transport/rtp/dependency_descriptor.cc54
-rw-r--r--third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h129
-rw-r--r--third_party/libwebrtc/api/transport/rtp/dependency_descriptor_gn/moz.build221
-rw-r--r--third_party/libwebrtc/api/transport/rtp/rtp_source.h111
-rw-r--r--third_party/libwebrtc/api/transport/rtp/rtp_source_gn/moz.build209
-rw-r--r--third_party/libwebrtc/api/transport/sctp_transport_factory_interface.h42
-rw-r--r--third_party/libwebrtc/api/transport/stun.cc1515
-rw-r--r--third_party/libwebrtc/api/transport/stun.h798
-rw-r--r--third_party/libwebrtc/api/transport/stun_types_gn/moz.build201
-rw-r--r--third_party/libwebrtc/api/transport/stun_unittest.cc1882
-rw-r--r--third_party/libwebrtc/api/transport/test/create_feedback_generator.cc23
-rw-r--r--third_party/libwebrtc/api/transport/test/create_feedback_generator.h21
-rw-r--r--third_party/libwebrtc/api/transport/test/feedback_generator_interface.h37
-rw-r--r--third_party/libwebrtc/api/transport/test/mock_network_control.h35
34 files changed, 7536 insertions, 0 deletions
diff --git a/third_party/libwebrtc/api/transport/BUILD.gn b/third_party/libwebrtc/api/transport/BUILD.gn
new file mode 100644
index 0000000000..e0b31122b2
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/BUILD.gn
@@ -0,0 +1,167 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../webrtc.gni")
+
+rtc_library("bitrate_settings") {
+ visibility = [ "*" ]
+ sources = [
+ "bitrate_settings.cc",
+ "bitrate_settings.h",
+ ]
+ deps = [ "../../rtc_base/system:rtc_export" ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("enums") {
+ visibility = [ "*" ]
+ sources = [ "enums.h" ]
+}
+
+rtc_library("network_control") {
+ visibility = [ "*" ]
+ sources = [
+ "network_control.h",
+ "network_types.cc",
+ "network_types.h",
+ ]
+
+ deps = [
+ "../../api:field_trials_view",
+ "../rtc_event_log",
+ "../units:data_rate",
+ "../units:data_size",
+ "../units:time_delta",
+ "../units:timestamp",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("field_trial_based_config") {
+ visibility = [ "*" ]
+ sources = [
+ "field_trial_based_config.cc",
+ "field_trial_based_config.h",
+ ]
+ deps = [
+ "../../api:field_trials_registry",
+ "../../system_wrappers:field_trial",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_source_set("datagram_transport_interface") {
+ visibility = [ "*" ]
+ sources = [ "data_channel_transport_interface.h" ]
+ deps = [
+ "..:array_view",
+ "..:rtc_error",
+ "../../rtc_base:copy_on_write_buffer",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("goog_cc") {
+ visibility = [ "*" ]
+ sources = [
+ "goog_cc_factory.cc",
+ "goog_cc_factory.h",
+ ]
+ deps = [
+ ":network_control",
+ "..:network_state_predictor_api",
+ "../../api:field_trials_view",
+ "../../modules/congestion_controller/goog_cc",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
+}
+
+rtc_source_set("sctp_transport_factory_interface") {
+ visibility = [ "*" ]
+ sources = [ "sctp_transport_factory_interface.h" ]
+}
+
+rtc_source_set("stun_types") {
+if (!build_with_mozilla) {
+ visibility = [ "*" ]
+ sources = [
+ "stun.cc",
+ "stun.h",
+ ]
+
+ deps = [
+ "../../api:array_view",
+ "../../rtc_base:byte_buffer",
+ "../../rtc_base:byte_order",
+ "../../rtc_base:checks",
+ "../../rtc_base:crc32",
+ "../../rtc_base:ip_address",
+ "../../rtc_base:logging",
+ "../../rtc_base:socket_address",
+ "../../rtc_base:ssl",
+ "../../system_wrappers:metrics",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("test_feedback_generator_interface") {
+ testonly = true
+ sources = [ "test/feedback_generator_interface.h" ]
+ deps = [
+ ":network_control",
+ "..:simulated_network_api",
+ ]
+ }
+ rtc_library("test_feedback_generator") {
+ testonly = true
+ sources = [
+ "test/create_feedback_generator.cc",
+ "test/create_feedback_generator.h",
+ ]
+ visibility = [ "*" ]
+ deps = [
+ ":network_control",
+ ":test_feedback_generator_interface",
+ "../../test/network:feedback_generator",
+ ]
+ }
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("stun_unittest") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [ "stun_unittest.cc" ]
+ deps = [
+ ":stun_types",
+ "../../rtc_base:byte_buffer",
+ "../../rtc_base:byte_order",
+ "../../rtc_base:macromagic",
+ "../../rtc_base:socket_address",
+ "../../system_wrappers:metrics",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("mock_network_control") {
+ testonly = true
+ sources = [ "test/mock_network_control.h" ]
+ deps = [
+ ":network_control",
+ "../../test:test_support",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/api/transport/DEPS b/third_party/libwebrtc/api/transport/DEPS
new file mode 100644
index 0000000000..53a68e0e85
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/DEPS
@@ -0,0 +1,7 @@
+specific_include_rules = {
+ "stun\.h": [
+ "+rtc_base/byte_buffer.h",
+ "+rtc_base/ip_address.h",
+ "+rtc_base/socket_address.h",
+ ],
+}
diff --git a/third_party/libwebrtc/api/transport/OWNERS b/third_party/libwebrtc/api/transport/OWNERS
new file mode 100644
index 0000000000..5991f6fc56
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/OWNERS
@@ -0,0 +1,2 @@
+srte@webrtc.org
+terelius@webrtc.org
diff --git a/third_party/libwebrtc/api/transport/bitrate_settings.cc b/third_party/libwebrtc/api/transport/bitrate_settings.cc
new file mode 100644
index 0000000000..c72bd82791
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/bitrate_settings.cc
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/bitrate_settings.h"
+
+namespace webrtc {
+
+BitrateSettings::BitrateSettings() = default;
+BitrateSettings::~BitrateSettings() = default;
+BitrateSettings::BitrateSettings(const BitrateSettings&) = default;
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/bitrate_settings.h b/third_party/libwebrtc/api/transport/bitrate_settings.h
new file mode 100644
index 0000000000..562309a46c
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/bitrate_settings.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_BITRATE_SETTINGS_H_
+#define API_TRANSPORT_BITRATE_SETTINGS_H_
+
+#include <algorithm>
+
+#include "absl/types/optional.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// Configuration of send bitrate. The `start_bitrate_bps` value is
+// used for multiple purposes, both as a prior in the bandwidth
+// estimator, and for initial configuration of the encoder. We may
+// want to create separate apis for those, and use a smaller struct
+// with only the min and max constraints.
+struct RTC_EXPORT BitrateSettings {
+ BitrateSettings();
+ ~BitrateSettings();
+ BitrateSettings(const BitrateSettings&);
+ // 0 <= min <= start <= max should hold for set parameters.
+ absl::optional<int> min_bitrate_bps;
+ absl::optional<int> start_bitrate_bps;
+ absl::optional<int> max_bitrate_bps;
+};
+
+// TODO(srte): BitrateConstraints and BitrateSettings should be merged.
+// Both represent the same kind data, but are using different default
+// initializer and representation of unset values.
+struct BitrateConstraints {
+ int min_bitrate_bps = 0;
+ int start_bitrate_bps = kDefaultStartBitrateBps;
+ int max_bitrate_bps = -1;
+
+ private:
+ static constexpr int kDefaultStartBitrateBps = 300000;
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_BITRATE_SETTINGS_H_
diff --git a/third_party/libwebrtc/api/transport/bitrate_settings_gn/moz.build b/third_party/libwebrtc/api/transport/bitrate_settings_gn/moz.build
new file mode 100644
index 0000000000..fba5b45a5d
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/bitrate_settings_gn/moz.build
@@ -0,0 +1,217 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/transport/bitrate_settings.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("bitrate_settings_gn")
diff --git a/third_party/libwebrtc/api/transport/data_channel_transport_interface.h b/third_party/libwebrtc/api/transport/data_channel_transport_interface.h
new file mode 100644
index 0000000000..cdae6fee19
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/data_channel_transport_interface.h
@@ -0,0 +1,125 @@
+/* Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// This is an experimental interface and is subject to change without notice.
+
+#ifndef API_TRANSPORT_DATA_CHANNEL_TRANSPORT_INTERFACE_H_
+#define API_TRANSPORT_DATA_CHANNEL_TRANSPORT_INTERFACE_H_
+
+#include "absl/types/optional.h"
+#include "api/rtc_error.h"
+#include "rtc_base/copy_on_write_buffer.h"
+
+namespace webrtc {
+
+// Supported types of application data messages.
+enum class DataMessageType {
+ // Application data buffer with the binary bit unset.
+ kText,
+
+ // Application data buffer with the binary bit set.
+ kBinary,
+
+ // Transport-agnostic control messages, such as open or open-ack messages.
+ kControl,
+};
+
+// Parameters for sending data. The parameters may change from message to
+// message, even within a single channel. For example, control messages may be
+// sent reliably and in-order, even if the data channel is configured for
+// unreliable delivery.
+struct SendDataParams {
+ DataMessageType type = DataMessageType::kText;
+
+ // Whether to deliver the message in order with respect to other ordered
+ // messages with the same channel_id.
+ bool ordered = false;
+
+ // If set, the maximum number of times this message may be
+ // retransmitted by the transport before it is dropped.
+ // Setting this value to zero disables retransmission.
+ // Valid values are in the range [0-UINT16_MAX].
+ // `max_rtx_count` and `max_rtx_ms` may not be set simultaneously.
+ absl::optional<int> max_rtx_count;
+
+ // If set, the maximum number of milliseconds for which the transport
+ // may retransmit this message before it is dropped.
+ // Setting this value to zero disables retransmission.
+ // Valid values are in the range [0-UINT16_MAX].
+ // `max_rtx_count` and `max_rtx_ms` may not be set simultaneously.
+ absl::optional<int> max_rtx_ms;
+};
+
+// Sink for callbacks related to a data channel.
+class DataChannelSink {
+ public:
+ virtual ~DataChannelSink() = default;
+
+ // Callback issued when data is received by the transport.
+ virtual void OnDataReceived(int channel_id,
+ DataMessageType type,
+ const rtc::CopyOnWriteBuffer& buffer) = 0;
+
+ // Callback issued when a remote data channel begins the closing procedure.
+ // Messages sent after the closing procedure begins will not be transmitted.
+ virtual void OnChannelClosing(int channel_id) = 0;
+
+ // Callback issued when a (remote or local) data channel completes the closing
+ // procedure. Closing channels become closed after all pending data has been
+ // transmitted.
+ virtual void OnChannelClosed(int channel_id) = 0;
+
+ // Callback issued when the data channel becomes ready to send.
+ // This callback will be issued immediately when the data channel sink is
+ // registered if the transport is ready at that time. This callback may be
+ // invoked again following send errors (eg. due to the transport being
+ // temporarily blocked or unavailable).
+ virtual void OnReadyToSend() = 0;
+
+ // Callback issued when the data channel becomes unusable (closed).
+ // TODO(https://crbug.com/webrtc/10360): Make pure virtual when all
+ // consumers updated.
+ virtual void OnTransportClosed(RTCError error) {}
+};
+
+// Transport for data channels.
+class DataChannelTransportInterface {
+ public:
+ virtual ~DataChannelTransportInterface() = default;
+
+ // Opens a data `channel_id` for sending. May return an error if the
+ // specified `channel_id` is unusable. Must be called before `SendData`.
+ virtual RTCError OpenChannel(int channel_id) = 0;
+
+ // Sends a data buffer to the remote endpoint using the given send parameters.
+ // `buffer` may not be larger than 256 KiB. Returns an error if the send
+ // fails.
+ virtual RTCError SendData(int channel_id,
+ const SendDataParams& params,
+ const rtc::CopyOnWriteBuffer& buffer) = 0;
+
+ // Closes `channel_id` gracefully. Returns an error if `channel_id` is not
+ // open. Data sent after the closing procedure begins will not be
+ // transmitted. The channel becomes closed after pending data is transmitted.
+ virtual RTCError CloseChannel(int channel_id) = 0;
+
+ // Sets a sink for data messages and channel state callbacks. Before media
+ // transport is destroyed, the sink must be unregistered by setting it to
+ // nullptr.
+ virtual void SetDataSink(DataChannelSink* sink) = 0;
+
+ // Returns whether this data channel transport is ready to send.
+ // Note: the default implementation always returns false (as it assumes no one
+ // has implemented the interface). This default implementation is temporary.
+ virtual bool IsReadyToSend() const = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_DATA_CHANNEL_TRANSPORT_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/transport/datagram_transport_interface_gn/moz.build b/third_party/libwebrtc/api/transport/datagram_transport_interface_gn/moz.build
new file mode 100644
index 0000000000..ac59bcbcde
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/datagram_transport_interface_gn/moz.build
@@ -0,0 +1,209 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("datagram_transport_interface_gn")
diff --git a/third_party/libwebrtc/api/transport/enums.h b/third_party/libwebrtc/api/transport/enums.h
new file mode 100644
index 0000000000..3bc8fd1529
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/enums.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_ENUMS_H_
+#define API_TRANSPORT_ENUMS_H_
+
+namespace webrtc {
+
+// See https://w3c.github.io/webrtc-pc/#rtcicetransportstate
+// Note that kFailed is currently not a terminal state, and a transport might
+// incorrectly be marked as failed while gathering candidates, see
+// bugs.webrtc.org/8833
+enum class IceTransportState {
+ kNew,
+ kChecking,
+ kConnected,
+ kCompleted,
+ kFailed,
+ kDisconnected,
+ kClosed,
+};
+
+enum PortPrunePolicy {
+ NO_PRUNE, // Do not prune.
+ PRUNE_BASED_ON_PRIORITY, // Prune lower-priority ports on the same network.
+ KEEP_FIRST_READY // Keep the first ready port and prune the rest
+ // on the same network.
+};
+
+enum class VpnPreference {
+ kDefault, // No VPN preference.
+ kOnlyUseVpn, // only use VPN connections.
+ kNeverUseVpn, // never use VPN connections
+ kPreferVpn, // use a VPN connection if possible,
+ // i.e VPN connections sorts first.
+ kAvoidVpn, // only use VPN if there is no other connections,
+ // i.e VPN connections sorts last.
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_ENUMS_H_
diff --git a/third_party/libwebrtc/api/transport/field_trial_based_config.cc b/third_party/libwebrtc/api/transport/field_trial_based_config.cc
new file mode 100644
index 0000000000..0cef30f054
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/field_trial_based_config.cc
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/transport/field_trial_based_config.h"
+
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+std::string FieldTrialBasedConfig::GetValue(absl::string_view key) const {
+ return webrtc::field_trial::FindFullName(std::string(key));
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/field_trial_based_config.h b/third_party/libwebrtc/api/transport/field_trial_based_config.h
new file mode 100644
index 0000000000..d47140e579
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/field_trial_based_config.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
+#define API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/field_trials_registry.h"
+
+namespace webrtc {
+// Implementation using the field trial API fo the key value lookup.
+class FieldTrialBasedConfig : public FieldTrialsRegistry {
+ private:
+ std::string GetValue(absl::string_view key) const override;
+};
+} // namespace webrtc
+
+#endif // API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
diff --git a/third_party/libwebrtc/api/transport/field_trial_based_config_gn/moz.build b/third_party/libwebrtc/api/transport/field_trial_based_config_gn/moz.build
new file mode 100644
index 0000000000..1ef79b4d20
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/field_trial_based_config_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/transport/field_trial_based_config.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("field_trial_based_config_gn")
diff --git a/third_party/libwebrtc/api/transport/goog_cc_factory.cc b/third_party/libwebrtc/api/transport/goog_cc_factory.cc
new file mode 100644
index 0000000000..fd1189901f
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/goog_cc_factory.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/goog_cc_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "modules/congestion_controller/goog_cc/goog_cc_network_control.h"
+
+namespace webrtc {
+GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
+ RtcEventLog* event_log)
+ : event_log_(event_log) {}
+
+GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
+ NetworkStatePredictorFactoryInterface* network_state_predictor_factory) {
+ factory_config_.network_state_predictor_factory =
+ network_state_predictor_factory;
+}
+
+GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
+ GoogCcFactoryConfig config)
+ : factory_config_(std::move(config)) {}
+
+std::unique_ptr<NetworkControllerInterface>
+GoogCcNetworkControllerFactory::Create(NetworkControllerConfig config) {
+ if (event_log_)
+ config.event_log = event_log_;
+ GoogCcConfig goog_cc_config;
+ goog_cc_config.feedback_only = factory_config_.feedback_only;
+ if (factory_config_.network_state_estimator_factory) {
+ RTC_DCHECK(config.key_value_config);
+ goog_cc_config.network_state_estimator =
+ factory_config_.network_state_estimator_factory->Create(
+ config.key_value_config);
+ }
+ if (factory_config_.network_state_predictor_factory) {
+ goog_cc_config.network_state_predictor =
+ factory_config_.network_state_predictor_factory
+ ->CreateNetworkStatePredictor();
+ }
+ return std::make_unique<GoogCcNetworkController>(config,
+ std::move(goog_cc_config));
+}
+
+TimeDelta GoogCcNetworkControllerFactory::GetProcessInterval() const {
+ const int64_t kUpdateIntervalMs = 25;
+ return TimeDelta::Millis(kUpdateIntervalMs);
+}
+
+GoogCcFeedbackNetworkControllerFactory::GoogCcFeedbackNetworkControllerFactory(
+ RtcEventLog* event_log)
+ : GoogCcNetworkControllerFactory(event_log) {
+ factory_config_.feedback_only = true;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/goog_cc_factory.h b/third_party/libwebrtc/api/transport/goog_cc_factory.h
new file mode 100644
index 0000000000..e12755d745
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/goog_cc_factory.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_GOOG_CC_FACTORY_H_
+#define API_TRANSPORT_GOOG_CC_FACTORY_H_
+#include <memory>
+
+#include "absl/base/attributes.h"
+#include "api/network_state_predictor.h"
+#include "api/transport/network_control.h"
+
+namespace webrtc {
+class RtcEventLog;
+
+struct GoogCcFactoryConfig {
+ std::unique_ptr<NetworkStateEstimatorFactory>
+ network_state_estimator_factory = nullptr;
+ NetworkStatePredictorFactoryInterface* network_state_predictor_factory =
+ nullptr;
+ bool feedback_only = false;
+};
+
+class GoogCcNetworkControllerFactory
+ : public NetworkControllerFactoryInterface {
+ public:
+ GoogCcNetworkControllerFactory() = default;
+ ABSL_DEPRECATED("")
+ explicit GoogCcNetworkControllerFactory(RtcEventLog* event_log);
+ explicit GoogCcNetworkControllerFactory(
+ NetworkStatePredictorFactoryInterface* network_state_predictor_factory);
+
+ explicit GoogCcNetworkControllerFactory(GoogCcFactoryConfig config);
+ std::unique_ptr<NetworkControllerInterface> Create(
+ NetworkControllerConfig config) override;
+ TimeDelta GetProcessInterval() const override;
+
+ protected:
+ RtcEventLog* const event_log_ = nullptr;
+ GoogCcFactoryConfig factory_config_;
+};
+
+// Deprecated, use GoogCcFactoryConfig to enable feedback only mode instead.
+// Factory to create packet feedback only GoogCC, this can be used for
+// connections providing packet receive time feedback but no other reports.
+class ABSL_DEPRECATED("use GoogCcFactoryConfig instead")
+ GoogCcFeedbackNetworkControllerFactory
+ : public GoogCcNetworkControllerFactory {
+ public:
+ explicit GoogCcFeedbackNetworkControllerFactory(RtcEventLog* event_log);
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_GOOG_CC_FACTORY_H_
diff --git a/third_party/libwebrtc/api/transport/goog_cc_gn/moz.build b/third_party/libwebrtc/api/transport/goog_cc_gn/moz.build
new file mode 100644
index 0000000000..95cbec37f0
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/goog_cc_gn/moz.build
@@ -0,0 +1,232 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/transport/goog_cc_factory.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "crypt32",
+ "iphlpapi",
+ "secur32",
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("goog_cc_gn")
diff --git a/third_party/libwebrtc/api/transport/network_control.h b/third_party/libwebrtc/api/transport/network_control.h
new file mode 100644
index 0000000000..862322443d
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/network_control.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_NETWORK_CONTROL_H_
+#define API_TRANSPORT_NETWORK_CONTROL_H_
+#include <stdint.h>
+
+#include <memory>
+
+#include "absl/base/attributes.h"
+#include "api/field_trials_view.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/transport/network_types.h"
+
+namespace webrtc {
+
+class TargetTransferRateObserver {
+ public:
+ virtual ~TargetTransferRateObserver() = default;
+ // Called to indicate target transfer rate as well as giving information about
+ // the current estimate of network parameters.
+ virtual void OnTargetTransferRate(TargetTransferRate) = 0;
+ // Called to provide updates to the expected target rate in case it changes
+ // before the first call to OnTargetTransferRate.
+ virtual void OnStartRateUpdate(DataRate) {}
+};
+
+// Configuration sent to factory create function. The parameters here are
+// optional to use for a network controller implementation.
+struct NetworkControllerConfig {
+ // The initial constraints to start with, these can be changed at any later
+ // time by calls to OnTargetRateConstraints. Note that the starting rate
+ // has to be set initially to provide a starting state for the network
+ // controller, even though the field is marked as optional.
+ TargetRateConstraints constraints;
+ // Initial stream specific configuration, these are changed at any later time
+ // by calls to OnStreamsConfig.
+ StreamsConfig stream_based_config;
+
+ // Optional override of configuration of WebRTC internals. Using nullptr here
+ // indicates that the field trial API will be used.
+ const FieldTrialsView* key_value_config = nullptr;
+ // Optional override of event log.
+ RtcEventLog* event_log = nullptr;
+};
+
+// NetworkControllerInterface is implemented by network controllers. A network
+// controller is a class that uses information about network state and traffic
+// to estimate network parameters such as round trip time and bandwidth. Network
+// controllers does not guarantee thread safety, the interface must be used in a
+// non-concurrent fashion.
+class NetworkControllerInterface {
+ public:
+ virtual ~NetworkControllerInterface() = default;
+
+ // Called when network availabilty changes.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnNetworkAvailability(
+ NetworkAvailability) = 0;
+ // Called when the receiving or sending endpoint changes address.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnNetworkRouteChange(
+ NetworkRouteChange) = 0;
+ // Called periodically with a periodicy as specified by
+ // NetworkControllerFactoryInterface::GetProcessInterval.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnProcessInterval(
+ ProcessInterval) = 0;
+ // Called when remotely calculated bitrate is received.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnRemoteBitrateReport(
+ RemoteBitrateReport) = 0;
+ // Called round trip time has been calculated by protocol specific mechanisms.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnRoundTripTimeUpdate(
+ RoundTripTimeUpdate) = 0;
+ // Called when a packet is sent on the network.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnSentPacket(
+ SentPacket) = 0;
+ // Called when a packet is received from the remote client.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnReceivedPacket(
+ ReceivedPacket) = 0;
+ // Called when the stream specific configuration has been updated.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnStreamsConfig(
+ StreamsConfig) = 0;
+ // Called when target transfer rate constraints has been changed.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnTargetRateConstraints(
+ TargetRateConstraints) = 0;
+ // Called when a protocol specific calculation of packet loss has been made.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnTransportLossReport(
+ TransportLossReport) = 0;
+ // Called with per packet feedback regarding receive time.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnTransportPacketsFeedback(
+ TransportPacketsFeedback) = 0;
+ // Called with network state estimate updates.
+ ABSL_MUST_USE_RESULT virtual NetworkControlUpdate OnNetworkStateEstimate(
+ NetworkStateEstimate) = 0;
+};
+
+// NetworkControllerFactoryInterface is an interface for creating a network
+// controller.
+class NetworkControllerFactoryInterface {
+ public:
+ virtual ~NetworkControllerFactoryInterface() = default;
+
+ // Used to create a new network controller, requires an observer to be
+ // provided to handle callbacks.
+ virtual std::unique_ptr<NetworkControllerInterface> Create(
+ NetworkControllerConfig config) = 0;
+ // Returns the interval by which the network controller expects
+ // OnProcessInterval calls.
+ virtual TimeDelta GetProcessInterval() const = 0;
+};
+
+// Under development, subject to change without notice.
+class NetworkStateEstimator {
+ public:
+ // Gets the current best estimate according to the estimator.
+ virtual absl::optional<NetworkStateEstimate> GetCurrentEstimate() = 0;
+ // Called with per packet feedback regarding receive time.
+ // Used when the NetworkStateEstimator runs in the sending endpoint.
+ virtual void OnTransportPacketsFeedback(const TransportPacketsFeedback&) = 0;
+ // Called with per packet feedback regarding receive time.
+ // Used when the NetworkStateEstimator runs in the receiving endpoint.
+ virtual void OnReceivedPacket(const PacketResult&) {}
+ // Called when the receiving or sending endpoint changes address.
+ virtual void OnRouteChange(const NetworkRouteChange&) = 0;
+ virtual ~NetworkStateEstimator() = default;
+};
+class NetworkStateEstimatorFactory {
+ public:
+ virtual std::unique_ptr<NetworkStateEstimator> Create(
+ const FieldTrialsView* key_value_config) = 0;
+ virtual ~NetworkStateEstimatorFactory() = default;
+};
+} // namespace webrtc
+
+#endif // API_TRANSPORT_NETWORK_CONTROL_H_
diff --git a/third_party/libwebrtc/api/transport/network_control_gn/moz.build b/third_party/libwebrtc/api/transport/network_control_gn/moz.build
new file mode 100644
index 0000000000..181843597f
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/network_control_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/transport/network_types.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("network_control_gn")
diff --git a/third_party/libwebrtc/api/transport/network_types.cc b/third_party/libwebrtc/api/transport/network_types.cc
new file mode 100644
index 0000000000..d6495ce490
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/network_types.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/network_types.h"
+
+#include <algorithm>
+
+namespace webrtc {
+StreamsConfig::StreamsConfig() = default;
+StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
+StreamsConfig::~StreamsConfig() = default;
+
+TargetRateConstraints::TargetRateConstraints() = default;
+TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) =
+ default;
+TargetRateConstraints::~TargetRateConstraints() = default;
+
+NetworkRouteChange::NetworkRouteChange() = default;
+NetworkRouteChange::NetworkRouteChange(const NetworkRouteChange&) = default;
+NetworkRouteChange::~NetworkRouteChange() = default;
+
+PacketResult::PacketResult() = default;
+PacketResult::PacketResult(const PacketResult& other) = default;
+PacketResult::~PacketResult() = default;
+
+bool PacketResult::ReceiveTimeOrder::operator()(const PacketResult& lhs,
+ const PacketResult& rhs) {
+ if (lhs.receive_time != rhs.receive_time)
+ return lhs.receive_time < rhs.receive_time;
+ if (lhs.sent_packet.send_time != rhs.sent_packet.send_time)
+ return lhs.sent_packet.send_time < rhs.sent_packet.send_time;
+ return lhs.sent_packet.sequence_number < rhs.sent_packet.sequence_number;
+}
+
+TransportPacketsFeedback::TransportPacketsFeedback() = default;
+TransportPacketsFeedback::TransportPacketsFeedback(
+ const TransportPacketsFeedback& other) = default;
+TransportPacketsFeedback::~TransportPacketsFeedback() = default;
+
+std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
+ const {
+ std::vector<PacketResult> res;
+ for (const PacketResult& fb : packet_feedbacks) {
+ if (fb.IsReceived()) {
+ res.push_back(fb);
+ }
+ }
+ return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
+ std::vector<PacketResult> res;
+ for (const PacketResult& fb : packet_feedbacks) {
+ if (!fb.IsReceived()) {
+ res.push_back(fb);
+ }
+ }
+ return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
+ const {
+ return packet_feedbacks;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::SortedByReceiveTime()
+ const {
+ std::vector<PacketResult> res;
+ for (const PacketResult& fb : packet_feedbacks) {
+ if (fb.IsReceived()) {
+ res.push_back(fb);
+ }
+ }
+ std::sort(res.begin(), res.end(), PacketResult::ReceiveTimeOrder());
+ return res;
+}
+
+NetworkControlUpdate::NetworkControlUpdate() = default;
+NetworkControlUpdate::NetworkControlUpdate(const NetworkControlUpdate&) =
+ default;
+NetworkControlUpdate::~NetworkControlUpdate() = default;
+
+PacedPacketInfo::PacedPacketInfo() = default;
+
+PacedPacketInfo::PacedPacketInfo(int probe_cluster_id,
+ int probe_cluster_min_probes,
+ int probe_cluster_min_bytes)
+ : probe_cluster_id(probe_cluster_id),
+ probe_cluster_min_probes(probe_cluster_min_probes),
+ probe_cluster_min_bytes(probe_cluster_min_bytes) {}
+
+bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const {
+ return send_bitrate_bps == rhs.send_bitrate_bps &&
+ probe_cluster_id == rhs.probe_cluster_id &&
+ probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
+ probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/network_types.h b/third_party/libwebrtc/api/transport/network_types.h
new file mode 100644
index 0000000000..29a7cf7705
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/network_types.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_NETWORK_TYPES_H_
+#define API_TRANSPORT_NETWORK_TYPES_H_
+#include <stdint.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+
+// Configuration
+
+// Represents constraints and rates related to the currently enabled streams.
+// This is used as input to the congestion controller via the StreamsConfig
+// struct.
+struct BitrateAllocationLimits {
+ // The total minimum send bitrate required by all sending streams.
+ DataRate min_allocatable_rate = DataRate::Zero();
+ // The total maximum allocatable bitrate for all currently available streams.
+ DataRate max_allocatable_rate = DataRate::Zero();
+ // The max bitrate to use for padding. The sum of the per-stream max padding
+ // rate.
+ DataRate max_padding_rate = DataRate::Zero();
+};
+
+// Use StreamsConfig for information about streams that is required for specific
+// adjustments to the algorithms in network controllers. Especially useful
+// for experiments.
+struct StreamsConfig {
+ StreamsConfig();
+ StreamsConfig(const StreamsConfig&);
+ ~StreamsConfig();
+ Timestamp at_time = Timestamp::PlusInfinity();
+ absl::optional<bool> requests_alr_probing;
+ absl::optional<double> pacing_factor;
+
+ // TODO(srte): Use BitrateAllocationLimits here.
+ absl::optional<DataRate> min_total_allocated_bitrate;
+ absl::optional<DataRate> max_padding_rate;
+ absl::optional<DataRate> max_total_allocated_bitrate;
+};
+
+struct TargetRateConstraints {
+ TargetRateConstraints();
+ TargetRateConstraints(const TargetRateConstraints&);
+ ~TargetRateConstraints();
+ Timestamp at_time = Timestamp::PlusInfinity();
+ absl::optional<DataRate> min_data_rate;
+ absl::optional<DataRate> max_data_rate;
+ // The initial bandwidth estimate to base target rate on. This should be used
+ // as the basis for initial OnTargetTransferRate and OnPacerConfig callbacks.
+ absl::optional<DataRate> starting_rate;
+};
+
+// Send side information
+
+struct NetworkAvailability {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ bool network_available = false;
+};
+
+struct NetworkRouteChange {
+ NetworkRouteChange();
+ NetworkRouteChange(const NetworkRouteChange&);
+ ~NetworkRouteChange();
+ Timestamp at_time = Timestamp::PlusInfinity();
+ // The TargetRateConstraints are set here so they can be changed synchronously
+ // when network route changes.
+ TargetRateConstraints constraints;
+};
+
+struct PacedPacketInfo {
+ PacedPacketInfo();
+ PacedPacketInfo(int probe_cluster_id,
+ int probe_cluster_min_probes,
+ int probe_cluster_min_bytes);
+
+ bool operator==(const PacedPacketInfo& rhs) const;
+
+ // TODO(srte): Move probing info to a separate, optional struct.
+ static constexpr int kNotAProbe = -1;
+ int send_bitrate_bps = -1;
+ int probe_cluster_id = kNotAProbe;
+ int probe_cluster_min_probes = -1;
+ int probe_cluster_min_bytes = -1;
+ int probe_cluster_bytes_sent = 0;
+};
+
+struct SentPacket {
+ Timestamp send_time = Timestamp::PlusInfinity();
+ // Size of packet with overhead up to IP layer.
+ DataSize size = DataSize::Zero();
+ // Size of preceeding packets that are not part of feedback.
+ DataSize prior_unacked_data = DataSize::Zero();
+ // Probe cluster id and parameters including bitrate, number of packets and
+ // number of bytes.
+ PacedPacketInfo pacing_info;
+ // True if the packet is an audio packet, false for video, padding, RTX etc.
+ bool audio = false;
+ // Transport independent sequence number, any tracked packet should have a
+ // sequence number that is unique over the whole call and increasing by 1 for
+ // each packet.
+ int64_t sequence_number;
+ // Tracked data in flight when the packet was sent, excluding unacked data.
+ DataSize data_in_flight = DataSize::Zero();
+};
+
+struct ReceivedPacket {
+ Timestamp send_time = Timestamp::MinusInfinity();
+ Timestamp receive_time = Timestamp::PlusInfinity();
+ DataSize size = DataSize::Zero();
+};
+
+// Transport level feedback
+
+struct RemoteBitrateReport {
+ Timestamp receive_time = Timestamp::PlusInfinity();
+ DataRate bandwidth = DataRate::Infinity();
+};
+
+struct RoundTripTimeUpdate {
+ Timestamp receive_time = Timestamp::PlusInfinity();
+ TimeDelta round_trip_time = TimeDelta::PlusInfinity();
+ bool smoothed = false;
+};
+
+struct TransportLossReport {
+ Timestamp receive_time = Timestamp::PlusInfinity();
+ Timestamp start_time = Timestamp::PlusInfinity();
+ Timestamp end_time = Timestamp::PlusInfinity();
+ uint64_t packets_lost_delta = 0;
+ uint64_t packets_received_delta = 0;
+};
+
+// Packet level feedback
+
+struct PacketResult {
+ class ReceiveTimeOrder {
+ public:
+ bool operator()(const PacketResult& lhs, const PacketResult& rhs);
+ };
+
+ PacketResult();
+ PacketResult(const PacketResult&);
+ ~PacketResult();
+
+ inline bool IsReceived() const { return !receive_time.IsPlusInfinity(); }
+
+ SentPacket sent_packet;
+ Timestamp receive_time = Timestamp::PlusInfinity();
+};
+
+struct TransportPacketsFeedback {
+ TransportPacketsFeedback();
+ TransportPacketsFeedback(const TransportPacketsFeedback& other);
+ ~TransportPacketsFeedback();
+
+ Timestamp feedback_time = Timestamp::PlusInfinity();
+ Timestamp first_unacked_send_time = Timestamp::PlusInfinity();
+ DataSize data_in_flight = DataSize::Zero();
+ DataSize prior_in_flight = DataSize::Zero();
+ std::vector<PacketResult> packet_feedbacks;
+
+ // Arrival times for messages without send time information.
+ std::vector<Timestamp> sendless_arrival_times;
+
+ std::vector<PacketResult> ReceivedWithSendInfo() const;
+ std::vector<PacketResult> LostWithSendInfo() const;
+ std::vector<PacketResult> PacketsWithFeedback() const;
+ std::vector<PacketResult> SortedByReceiveTime() const;
+};
+
+// Network estimation
+
+struct NetworkEstimate {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ // Deprecated, use TargetTransferRate::target_rate instead.
+ DataRate bandwidth = DataRate::Infinity();
+ TimeDelta round_trip_time = TimeDelta::PlusInfinity();
+ TimeDelta bwe_period = TimeDelta::PlusInfinity();
+
+ float loss_rate_ratio = 0;
+};
+
+// Network control
+
+struct PacerConfig {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ // Pacer should send at most data_window data over time_window duration.
+ DataSize data_window = DataSize::Infinity();
+ TimeDelta time_window = TimeDelta::PlusInfinity();
+ // Pacer should send at least pad_window data over time_window duration.
+ DataSize pad_window = DataSize::Zero();
+ DataRate data_rate() const { return data_window / time_window; }
+ DataRate pad_rate() const { return pad_window / time_window; }
+};
+
+struct ProbeClusterConfig {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ DataRate target_data_rate = DataRate::Zero();
+ TimeDelta target_duration = TimeDelta::Zero();
+ int32_t target_probe_count = 0;
+ int32_t id = 0;
+};
+
+struct TargetTransferRate {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ // The estimate on which the target rate is based on.
+ NetworkEstimate network_estimate;
+ DataRate target_rate = DataRate::Zero();
+ DataRate stable_target_rate = DataRate::Zero();
+ double cwnd_reduce_ratio = 0;
+};
+
+// Contains updates of network controller comand state. Using optionals to
+// indicate whether a member has been updated. The array of probe clusters
+// should be used to send out probes if not empty.
+struct NetworkControlUpdate {
+ NetworkControlUpdate();
+ NetworkControlUpdate(const NetworkControlUpdate&);
+ ~NetworkControlUpdate();
+ absl::optional<DataSize> congestion_window;
+ absl::optional<PacerConfig> pacer_config;
+ std::vector<ProbeClusterConfig> probe_cluster_configs;
+ absl::optional<TargetTransferRate> target_rate;
+};
+
+// Process control
+struct ProcessInterval {
+ Timestamp at_time = Timestamp::PlusInfinity();
+ absl::optional<DataSize> pacer_queue;
+};
+
+// Under development, subject to change without notice.
+struct NetworkStateEstimate {
+ double confidence = NAN;
+ // The time the estimate was received/calculated.
+ Timestamp update_time = Timestamp::MinusInfinity();
+ Timestamp last_receive_time = Timestamp::MinusInfinity();
+ Timestamp last_send_time = Timestamp::MinusInfinity();
+
+ // Total estimated link capacity.
+ DataRate link_capacity = DataRate::MinusInfinity();
+ // Used as a safe measure of available capacity.
+ DataRate link_capacity_lower = DataRate::MinusInfinity();
+ // Used as limit for increasing bitrate.
+ DataRate link_capacity_upper = DataRate::MinusInfinity();
+
+ TimeDelta pre_link_buffer_delay = TimeDelta::MinusInfinity();
+ TimeDelta post_link_buffer_delay = TimeDelta::MinusInfinity();
+ TimeDelta propagation_delay = TimeDelta::MinusInfinity();
+
+ // Only for debugging
+ TimeDelta time_delta = TimeDelta::MinusInfinity();
+ Timestamp last_feed_time = Timestamp::MinusInfinity();
+ double cross_delay_rate = NAN;
+ double spike_delay_rate = NAN;
+ DataRate link_capacity_std_dev = DataRate::MinusInfinity();
+ DataRate link_capacity_min = DataRate::MinusInfinity();
+ double cross_traffic_ratio = NAN;
+};
+} // namespace webrtc
+
+#endif // API_TRANSPORT_NETWORK_TYPES_H_
diff --git a/third_party/libwebrtc/api/transport/rtp/BUILD.gn b/third_party/libwebrtc/api/transport/rtp/BUILD.gn
new file mode 100644
index 0000000000..205bbcc988
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("rtp_source") {
+ visibility = [ "*" ]
+ sources = [ "rtp_source.h" ]
+ deps = [
+ "../../../api:rtp_headers",
+ "../../../api/units:time_delta",
+ "../../../rtc_base:checks",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("dependency_descriptor") {
+ visibility = [ "*" ]
+ sources = [
+ "dependency_descriptor.cc",
+ "dependency_descriptor.h",
+ ]
+ deps = [
+ "../../../rtc_base:checks",
+ "../../video:render_resolution",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/container:inlined_vector",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
diff --git a/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.cc b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.cc
new file mode 100644
index 0000000000..e784853cd6
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/rtp/dependency_descriptor.h"
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+constexpr int DependencyDescriptor::kMaxSpatialIds;
+constexpr int DependencyDescriptor::kMaxTemporalIds;
+constexpr int DependencyDescriptor::kMaxTemplates;
+constexpr int DependencyDescriptor::kMaxDecodeTargets;
+
+namespace webrtc_impl {
+
+absl::InlinedVector<DecodeTargetIndication, 10> StringToDecodeTargetIndications(
+ absl::string_view symbols) {
+ absl::InlinedVector<DecodeTargetIndication, 10> dtis;
+ dtis.reserve(symbols.size());
+ for (char symbol : symbols) {
+ DecodeTargetIndication indication;
+ switch (symbol) {
+ case '-':
+ indication = DecodeTargetIndication::kNotPresent;
+ break;
+ case 'D':
+ indication = DecodeTargetIndication::kDiscardable;
+ break;
+ case 'R':
+ indication = DecodeTargetIndication::kRequired;
+ break;
+ case 'S':
+ indication = DecodeTargetIndication::kSwitch;
+ break;
+ default:
+ RTC_DCHECK_NOTREACHED();
+ }
+ dtis.push_back(indication);
+ }
+ return dtis;
+}
+
+} // namespace webrtc_impl
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h
new file mode 100644
index 0000000000..0db600918e
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_RTP_DEPENDENCY_DESCRIPTOR_H_
+#define API_TRANSPORT_RTP_DEPENDENCY_DESCRIPTOR_H_
+
+#include <stdint.h>
+
+#include <initializer_list>
+#include <memory>
+#include <vector>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/video/render_resolution.h"
+
+namespace webrtc {
+// Structures to build and parse dependency descriptor as described in
+// https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension
+
+// Relationship of a frame to a Decode target.
+enum class DecodeTargetIndication {
+ kNotPresent = 0, // DecodeTargetInfo symbol '-'
+ kDiscardable = 1, // DecodeTargetInfo symbol 'D'
+ kSwitch = 2, // DecodeTargetInfo symbol 'S'
+ kRequired = 3 // DecodeTargetInfo symbol 'R'
+};
+
+struct FrameDependencyTemplate {
+ // Setters are named briefly to chain them when building the template.
+ FrameDependencyTemplate& S(int spatial_layer);
+ FrameDependencyTemplate& T(int temporal_layer);
+ FrameDependencyTemplate& Dtis(absl::string_view dtis);
+ FrameDependencyTemplate& FrameDiffs(std::initializer_list<int> diffs);
+ FrameDependencyTemplate& ChainDiffs(std::initializer_list<int> diffs);
+
+ friend bool operator==(const FrameDependencyTemplate& lhs,
+ const FrameDependencyTemplate& rhs) {
+ return lhs.spatial_id == rhs.spatial_id &&
+ lhs.temporal_id == rhs.temporal_id &&
+ lhs.decode_target_indications == rhs.decode_target_indications &&
+ lhs.frame_diffs == rhs.frame_diffs &&
+ lhs.chain_diffs == rhs.chain_diffs;
+ }
+
+ int spatial_id = 0;
+ int temporal_id = 0;
+ absl::InlinedVector<DecodeTargetIndication, 10> decode_target_indications;
+ absl::InlinedVector<int, 4> frame_diffs;
+ absl::InlinedVector<int, 4> chain_diffs;
+};
+
+struct FrameDependencyStructure {
+ friend bool operator==(const FrameDependencyStructure& lhs,
+ const FrameDependencyStructure& rhs) {
+ return lhs.num_decode_targets == rhs.num_decode_targets &&
+ lhs.num_chains == rhs.num_chains &&
+ lhs.decode_target_protected_by_chain ==
+ rhs.decode_target_protected_by_chain &&
+ lhs.resolutions == rhs.resolutions && lhs.templates == rhs.templates;
+ }
+
+ int structure_id = 0;
+ int num_decode_targets = 0;
+ int num_chains = 0;
+ // If chains are used (num_chains > 0), maps decode target index into index of
+ // the chain protecting that target.
+ absl::InlinedVector<int, 10> decode_target_protected_by_chain;
+ absl::InlinedVector<RenderResolution, 4> resolutions;
+ std::vector<FrameDependencyTemplate> templates;
+};
+
+struct DependencyDescriptor {
+ static constexpr int kMaxSpatialIds = 4;
+ static constexpr int kMaxTemporalIds = 8;
+ static constexpr int kMaxDecodeTargets = 32;
+ static constexpr int kMaxTemplates = 64;
+
+ bool first_packet_in_frame = true;
+ bool last_packet_in_frame = true;
+ int frame_number = 0;
+ FrameDependencyTemplate frame_dependencies;
+ absl::optional<RenderResolution> resolution;
+ absl::optional<uint32_t> active_decode_targets_bitmask;
+ std::unique_ptr<FrameDependencyStructure> attached_structure;
+};
+
+// Below are implementation details.
+namespace webrtc_impl {
+absl::InlinedVector<DecodeTargetIndication, 10> StringToDecodeTargetIndications(
+ absl::string_view indication_symbols);
+} // namespace webrtc_impl
+
+inline FrameDependencyTemplate& FrameDependencyTemplate::S(int spatial_layer) {
+ this->spatial_id = spatial_layer;
+ return *this;
+}
+inline FrameDependencyTemplate& FrameDependencyTemplate::T(int temporal_layer) {
+ this->temporal_id = temporal_layer;
+ return *this;
+}
+inline FrameDependencyTemplate& FrameDependencyTemplate::Dtis(
+ absl::string_view dtis) {
+ this->decode_target_indications =
+ webrtc_impl::StringToDecodeTargetIndications(dtis);
+ return *this;
+}
+inline FrameDependencyTemplate& FrameDependencyTemplate::FrameDiffs(
+ std::initializer_list<int> diffs) {
+ this->frame_diffs.assign(diffs.begin(), diffs.end());
+ return *this;
+}
+inline FrameDependencyTemplate& FrameDependencyTemplate::ChainDiffs(
+ std::initializer_list<int> diffs) {
+ this->chain_diffs.assign(diffs.begin(), diffs.end());
+ return *this;
+}
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_RTP_DEPENDENCY_DESCRIPTOR_H_
diff --git a/third_party/libwebrtc/api/transport/rtp/dependency_descriptor_gn/moz.build b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor_gn/moz.build
new file mode 100644
index 0000000000..0ee9e1fa1b
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/dependency_descriptor_gn/moz.build
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/api/transport/rtp/dependency_descriptor.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("dependency_descriptor_gn")
diff --git a/third_party/libwebrtc/api/transport/rtp/rtp_source.h b/third_party/libwebrtc/api/transport/rtp/rtp_source.h
new file mode 100644
index 0000000000..e51dcd70b6
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/rtp_source.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_RTP_RTP_SOURCE_H_
+#define API_TRANSPORT_RTP_RTP_SOURCE_H_
+
+#include <stdint.h>
+
+#include "absl/types/optional.h"
+#include "api/rtp_headers.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+enum class RtpSourceType {
+ SSRC,
+ CSRC,
+};
+
+class RtpSource {
+ public:
+ struct Extensions {
+ absl::optional<uint8_t> audio_level;
+
+ // Fields from the Absolute Capture Time header extension:
+ // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time;
+
+ // Clock offset between the local clock and the capturer's clock.
+ // Do not confuse with `AbsoluteCaptureTime::estimated_capture_clock_offset`
+ // which instead represents the clock offset between a remote sender and the
+ // capturer. The following holds:
+ // Capture's NTP Clock = Local NTP Clock + Local-Capture Clock Offset
+ absl::optional<TimeDelta> local_capture_clock_offset;
+ };
+
+ RtpSource() = delete;
+
+ RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type,
+ uint32_t rtp_timestamp,
+ const RtpSource::Extensions& extensions)
+ : timestamp_ms_(timestamp_ms),
+ source_id_(source_id),
+ source_type_(source_type),
+ extensions_(extensions),
+ rtp_timestamp_(rtp_timestamp) {}
+
+ RtpSource(const RtpSource&) = default;
+ RtpSource& operator=(const RtpSource&) = default;
+ ~RtpSource() = default;
+
+ int64_t timestamp_ms() const { return timestamp_ms_; }
+ void update_timestamp_ms(int64_t timestamp_ms) {
+ RTC_DCHECK_LE(timestamp_ms_, timestamp_ms);
+ timestamp_ms_ = timestamp_ms;
+ }
+
+ // The identifier of the source can be the CSRC or the SSRC.
+ uint32_t source_id() const { return source_id_; }
+
+ // The source can be either a contributing source or a synchronization source.
+ RtpSourceType source_type() const { return source_type_; }
+
+ absl::optional<uint8_t> audio_level() const {
+ return extensions_.audio_level;
+ }
+
+ void set_audio_level(const absl::optional<uint8_t>& level) {
+ extensions_.audio_level = level;
+ }
+
+ uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time() const {
+ return extensions_.absolute_capture_time;
+ }
+
+ absl::optional<TimeDelta> local_capture_clock_offset() const {
+ return extensions_.local_capture_clock_offset;
+ }
+
+ bool operator==(const RtpSource& o) const {
+ return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() &&
+ source_type_ == o.source_type() &&
+ extensions_.audio_level == o.extensions_.audio_level &&
+ extensions_.absolute_capture_time ==
+ o.extensions_.absolute_capture_time &&
+ rtp_timestamp_ == o.rtp_timestamp();
+ }
+
+ private:
+ int64_t timestamp_ms_;
+ uint32_t source_id_;
+ RtpSourceType source_type_;
+ RtpSource::Extensions extensions_;
+ uint32_t rtp_timestamp_;
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_RTP_RTP_SOURCE_H_
diff --git a/third_party/libwebrtc/api/transport/rtp/rtp_source_gn/moz.build b/third_party/libwebrtc/api/transport/rtp/rtp_source_gn/moz.build
new file mode 100644
index 0000000000..b43f4a77ec
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/rtp/rtp_source_gn/moz.build
@@ -0,0 +1,209 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("rtp_source_gn")
diff --git a/third_party/libwebrtc/api/transport/sctp_transport_factory_interface.h b/third_party/libwebrtc/api/transport/sctp_transport_factory_interface.h
new file mode 100644
index 0000000000..4fc8af5bad
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/sctp_transport_factory_interface.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_SCTP_TRANSPORT_FACTORY_INTERFACE_H_
+#define API_TRANSPORT_SCTP_TRANSPORT_FACTORY_INTERFACE_H_
+
+#include <memory>
+
+// These classes are not part of the API, and are treated as opaque pointers.
+namespace cricket {
+class SctpTransportInternal;
+} // namespace cricket
+
+namespace rtc {
+class PacketTransportInternal;
+} // namespace rtc
+
+namespace webrtc {
+
+// Factory class which can be used to allow fake SctpTransports to be injected
+// for testing. An application is not intended to implement this interface nor
+// 'cricket::SctpTransportInternal' because SctpTransportInternal is not
+// guaranteed to remain stable in future WebRTC versions.
+class SctpTransportFactoryInterface {
+ public:
+ virtual ~SctpTransportFactoryInterface() = default;
+
+ // Create an SCTP transport using `channel` for the underlying transport.
+ virtual std::unique_ptr<cricket::SctpTransportInternal> CreateSctpTransport(
+ rtc::PacketTransportInternal* channel) = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_SCTP_TRANSPORT_FACTORY_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/transport/stun.cc b/third_party/libwebrtc/api/transport/stun.cc
new file mode 100644
index 0000000000..1098c6720e
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/stun.cc
@@ -0,0 +1,1515 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/stun.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include "rtc_base/byte_order.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/crc32.h"
+#include "rtc_base/helpers.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/message_digest.h"
+#include "system_wrappers/include/metrics.h"
+
+using rtc::ByteBufferReader;
+using rtc::ByteBufferWriter;
+
+namespace cricket {
+
+namespace {
+
+const int k127Utf8CharactersLengthInBytes = 508;
+const int kMessageIntegrityAttributeLength = 20;
+const int kTheoreticalMaximumAttributeLength = 65535;
+
+uint32_t ReduceTransactionId(absl::string_view transaction_id) {
+ RTC_DCHECK(transaction_id.length() == cricket::kStunTransactionIdLength ||
+ transaction_id.length() == cricket::kStunLegacyTransactionIdLength)
+ << transaction_id.length();
+ ByteBufferReader reader(transaction_id.data(), transaction_id.size());
+ uint32_t result = 0;
+ uint32_t next;
+ while (reader.ReadUInt32(&next)) {
+ result ^= next;
+ }
+ return result;
+}
+
+// Check the maximum length of a BYTE_STRING attribute against specifications.
+bool LengthValid(int type, int length) {
+ // "Less than 509 bytes" is intended to indicate a maximum of 127
+ // UTF-8 characters, which may take up to 4 bytes per character.
+ switch (type) {
+ case STUN_ATTR_USERNAME:
+ return length <=
+ k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.3
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ return length ==
+ kMessageIntegrityAttributeLength; // RFC 8489 section 14.5
+ case STUN_ATTR_REALM:
+ return length <=
+ k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.9
+ case STUN_ATTR_NONCE:
+ return length <=
+ k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.10
+ case STUN_ATTR_SOFTWARE:
+ return length <=
+ k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14
+ case STUN_ATTR_DATA:
+ // No length restriction in RFC; it's the content of an UDP datagram,
+ // which in theory can be up to 65.535 bytes.
+ // TODO(bugs.webrtc.org/12179): Write a test to find the real limit.
+ return length <= kTheoreticalMaximumAttributeLength;
+ default:
+ // Return an arbitrary restriction for all other types.
+ return length <= kTheoreticalMaximumAttributeLength;
+ }
+ RTC_DCHECK_NOTREACHED();
+ return true;
+}
+
+} // namespace
+
+const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server";
+const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request";
+const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized";
+const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[] = "Unknown Attribute";
+const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden";
+const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch";
+const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce";
+const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials";
+const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol";
+const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict";
+const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error";
+
+const char TURN_MAGIC_COOKIE_VALUE[] = {'\x72', '\xC6', '\x4B', '\xC6'};
+const char EMPTY_TRANSACTION_ID[] = "0000000000000000";
+const uint32_t STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
+const int SERVER_NOT_REACHABLE_ERROR = 701;
+
+// StunMessage
+
+StunMessage::StunMessage()
+ : StunMessage(STUN_INVALID_MESSAGE_TYPE, EMPTY_TRANSACTION_ID) {}
+
+StunMessage::StunMessage(uint16_t type)
+ : StunMessage(type, GenerateTransactionId()) {}
+
+StunMessage::StunMessage(uint16_t type, absl::string_view transaction_id)
+ : type_(type),
+ transaction_id_(transaction_id),
+ reduced_transaction_id_(ReduceTransactionId(transaction_id_)) {
+ RTC_DCHECK(IsValidTransactionId(transaction_id_));
+}
+
+StunMessage::~StunMessage() = default;
+
+bool StunMessage::IsLegacy() const {
+ if (transaction_id_.size() == kStunLegacyTransactionIdLength)
+ return true;
+ RTC_DCHECK(transaction_id_.size() == kStunTransactionIdLength);
+ return false;
+}
+
+static bool DesignatedExpertRange(int attr_type) {
+ return (attr_type >= 0x4000 && attr_type <= 0x7FFF) ||
+ (attr_type >= 0xC000 && attr_type <= 0xFFFF);
+}
+
+void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
+ // Fail any attributes that aren't valid for this type of message,
+ // but allow any type for the range that in the RFC is reserved for
+ // the "designated experts".
+ if (!DesignatedExpertRange(attr->type())) {
+ RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
+ }
+
+ attr->SetOwner(this);
+ size_t attr_length = attr->length();
+ if (attr_length % 4 != 0) {
+ attr_length += (4 - (attr_length % 4));
+ }
+ length_ += static_cast<uint16_t>(attr_length + 4);
+
+ attrs_.push_back(std::move(attr));
+}
+
+std::unique_ptr<StunAttribute> StunMessage::RemoveAttribute(int type) {
+ std::unique_ptr<StunAttribute> attribute;
+ for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
+ if ((*it)->type() == type) {
+ attribute = std::move(*it);
+ attrs_.erase(std::next(it).base());
+ break;
+ }
+ }
+ if (attribute) {
+ attribute->SetOwner(nullptr);
+ size_t attr_length = attribute->length();
+ if (attr_length % 4 != 0) {
+ attr_length += (4 - (attr_length % 4));
+ }
+ length_ -= static_cast<uint16_t>(attr_length + 4);
+ }
+ return attribute;
+}
+
+void StunMessage::ClearAttributes() {
+ for (auto it = attrs_.rbegin(); it != attrs_.rend(); ++it) {
+ (*it)->SetOwner(nullptr);
+ }
+ attrs_.clear();
+ length_ = 0;
+}
+
+std::vector<uint16_t> StunMessage::GetNonComprehendedAttributes() const {
+ std::vector<uint16_t> unknown_attributes;
+ for (auto& attr : attrs_) {
+ // "comprehension-required" range is 0x0000-0x7FFF.
+ if (attr->type() >= 0x0000 && attr->type() <= 0x7FFF &&
+ GetAttributeValueType(attr->type()) == STUN_VALUE_UNKNOWN) {
+ unknown_attributes.push_back(attr->type());
+ }
+ }
+ return unknown_attributes;
+}
+
+const StunAddressAttribute* StunMessage::GetAddress(int type) const {
+ switch (type) {
+ case STUN_ATTR_MAPPED_ADDRESS: {
+ // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is
+ // missing.
+ const StunAttribute* mapped_address =
+ GetAttribute(STUN_ATTR_MAPPED_ADDRESS);
+ if (!mapped_address)
+ mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ return reinterpret_cast<const StunAddressAttribute*>(mapped_address);
+ }
+
+ default:
+ return static_cast<const StunAddressAttribute*>(GetAttribute(type));
+ }
+}
+
+const StunUInt32Attribute* StunMessage::GetUInt32(int type) const {
+ return static_cast<const StunUInt32Attribute*>(GetAttribute(type));
+}
+
+const StunUInt64Attribute* StunMessage::GetUInt64(int type) const {
+ return static_cast<const StunUInt64Attribute*>(GetAttribute(type));
+}
+
+const StunByteStringAttribute* StunMessage::GetByteString(int type) const {
+ return static_cast<const StunByteStringAttribute*>(GetAttribute(type));
+}
+
+const StunUInt16ListAttribute* StunMessage::GetUInt16List(int type) const {
+ return static_cast<const StunUInt16ListAttribute*>(GetAttribute(type));
+}
+
+const StunErrorCodeAttribute* StunMessage::GetErrorCode() const {
+ return static_cast<const StunErrorCodeAttribute*>(
+ GetAttribute(STUN_ATTR_ERROR_CODE));
+}
+
+int StunMessage::GetErrorCodeValue() const {
+ const StunErrorCodeAttribute* error_attribute = GetErrorCode();
+ return error_attribute ? error_attribute->code() : STUN_ERROR_GLOBAL_FAILURE;
+}
+
+const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const {
+ return static_cast<const StunUInt16ListAttribute*>(
+ GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES));
+}
+
+StunMessage::IntegrityStatus StunMessage::ValidateMessageIntegrity(
+ const std::string& password) {
+ RTC_DCHECK(integrity_ == IntegrityStatus::kNotSet)
+ << "Usage error: Verification should only be done once";
+ password_ = password;
+ if (GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
+ if (ValidateMessageIntegrityOfType(
+ STUN_ATTR_MESSAGE_INTEGRITY, kStunMessageIntegritySize,
+ buffer_.c_str(), buffer_.size(), password)) {
+ integrity_ = IntegrityStatus::kIntegrityOk;
+ } else {
+ integrity_ = IntegrityStatus::kIntegrityBad;
+ }
+ } else if (GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32)) {
+ if (ValidateMessageIntegrityOfType(
+ STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32, kStunMessageIntegrity32Size,
+ buffer_.c_str(), buffer_.size(), password)) {
+ integrity_ = IntegrityStatus::kIntegrityOk;
+ } else {
+ integrity_ = IntegrityStatus::kIntegrityBad;
+ }
+ } else {
+ integrity_ = IntegrityStatus::kNoIntegrity;
+ }
+ // Log the result of integrity checking. See crbug.com/1177125 for background.
+ // Convert args to integer for the benefit of the macros.
+ int bucket_count = static_cast<int>(IntegrityStatus::kMaxValue) + 1;
+ int integrity = static_cast<int>(integrity_);
+ if (IsStunRequestType(type_)) {
+ RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Request", integrity,
+ bucket_count);
+ } else if (IsStunSuccessResponseType(type_)) {
+ RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Response", integrity,
+ bucket_count);
+ } else if (IsStunIndicationType(type_)) {
+ RTC_HISTOGRAM_ENUMERATION("WebRTC.Stun.Integrity.Indication", integrity,
+ bucket_count);
+ } else {
+ RTC_DCHECK(IsStunErrorResponseType(type_));
+ auto* error_attribute = GetErrorCode();
+ if (!error_attribute) {
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.NoErrorAttribute", integrity,
+ bucket_count);
+ } else {
+ switch (error_attribute->code()) {
+ case STUN_ERROR_TRY_ALTERNATE:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.TryAlternate", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_BAD_REQUEST:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.BadRequest", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_UNAUTHORIZED:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.Unauthorized", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_UNKNOWN_ATTRIBUTE:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.UnknownAttribute", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_STALE_NONCE:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.StaleNonce", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_SERVER_ERROR:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.ServerError", integrity,
+ bucket_count);
+ break;
+ case STUN_ERROR_GLOBAL_FAILURE:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.GlobalFailure", integrity,
+ bucket_count);
+ break;
+ default:
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Stun.Integrity.ErrorResponse.ErrorOther", integrity,
+ bucket_count);
+ break;
+ }
+ }
+ }
+ return integrity_;
+}
+
+StunMessage::IntegrityStatus StunMessage::RevalidateMessageIntegrity(
+ const std::string& password) {
+ RTC_LOG(LS_INFO) << "Message revalidation, old status was "
+ << static_cast<int>(integrity_);
+ integrity_ = IntegrityStatus::kNotSet;
+ return ValidateMessageIntegrity(password);
+}
+
+bool StunMessage::ValidateMessageIntegrityForTesting(
+ const char* data,
+ size_t size,
+ const std::string& password) {
+ return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
+ kStunMessageIntegritySize, data, size,
+ password);
+}
+
+bool StunMessage::ValidateMessageIntegrity32ForTesting(
+ const char* data,
+ size_t size,
+ const std::string& password) {
+ return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
+ kStunMessageIntegrity32Size, data, size,
+ password);
+}
+
+// Deprecated
+bool StunMessage::ValidateMessageIntegrity(const char* data,
+ size_t size,
+ const std::string& password) {
+ return ValidateMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
+ kStunMessageIntegritySize, data, size,
+ password);
+}
+
+// Deprecated
+bool StunMessage::ValidateMessageIntegrity32(const char* data,
+ size_t size,
+ const std::string& password) {
+ return ValidateMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
+ kStunMessageIntegrity32Size, data, size,
+ password);
+}
+
+// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
+// procedure outlined in RFC 5389, section 15.4.
+bool StunMessage::ValidateMessageIntegrityOfType(int mi_attr_type,
+ size_t mi_attr_size,
+ const char* data,
+ size_t size,
+ const std::string& password) {
+ RTC_DCHECK(mi_attr_size <= kStunMessageIntegritySize);
+
+ // Verifying the size of the message.
+ if ((size % 4) != 0 || size < kStunHeaderSize) {
+ return false;
+ }
+
+ // Getting the message length from the STUN header.
+ uint16_t msg_length = rtc::GetBE16(&data[2]);
+ if (size != (msg_length + kStunHeaderSize)) {
+ return false;
+ }
+
+ // Finding Message Integrity attribute in stun message.
+ size_t current_pos = kStunHeaderSize;
+ bool has_message_integrity_attr = false;
+ while (current_pos + 4 <= size) {
+ uint16_t attr_type, attr_length;
+ // Getting attribute type and length.
+ attr_type = rtc::GetBE16(&data[current_pos]);
+ attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]);
+
+ // If M-I, sanity check it, and break out.
+ if (attr_type == mi_attr_type) {
+ if (attr_length != mi_attr_size ||
+ current_pos + sizeof(attr_type) + sizeof(attr_length) + attr_length >
+ size) {
+ return false;
+ }
+ has_message_integrity_attr = true;
+ break;
+ }
+
+ // Otherwise, skip to the next attribute.
+ current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
+ if ((attr_length % 4) != 0) {
+ current_pos += (4 - (attr_length % 4));
+ }
+ }
+
+ if (!has_message_integrity_attr) {
+ return false;
+ }
+
+ // Getting length of the message to calculate Message Integrity.
+ size_t mi_pos = current_pos;
+ std::unique_ptr<char[]> temp_data(new char[current_pos]);
+ memcpy(temp_data.get(), data, current_pos);
+ if (size > mi_pos + kStunAttributeHeaderSize + mi_attr_size) {
+ // Stun message has other attributes after message integrity.
+ // Adjust the length parameter in stun message to calculate HMAC.
+ size_t extra_offset =
+ size - (mi_pos + kStunAttributeHeaderSize + mi_attr_size);
+ size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
+
+ // Writing new length of the STUN message @ Message Length in temp buffer.
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // |0 0| STUN Message Type | Message Length |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ rtc::SetBE16(temp_data.get() + 2, static_cast<uint16_t>(new_adjusted_len));
+ }
+
+ char hmac[kStunMessageIntegritySize];
+ size_t ret =
+ rtc::ComputeHmac(rtc::DIGEST_SHA_1, password.c_str(), password.size(),
+ temp_data.get(), mi_pos, hmac, sizeof(hmac));
+ RTC_DCHECK(ret == sizeof(hmac));
+ if (ret != sizeof(hmac)) {
+ return false;
+ }
+
+ // Comparing the calculated HMAC with the one present in the message.
+ return memcmp(data + current_pos + kStunAttributeHeaderSize, hmac,
+ mi_attr_size) == 0;
+}
+
+bool StunMessage::AddMessageIntegrity(absl::string_view password) {
+ return AddMessageIntegrityOfType(STUN_ATTR_MESSAGE_INTEGRITY,
+ kStunMessageIntegritySize, password);
+}
+
+bool StunMessage::AddMessageIntegrity32(absl::string_view password) {
+ return AddMessageIntegrityOfType(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32,
+ kStunMessageIntegrity32Size, password);
+}
+
+bool StunMessage::AddMessageIntegrityOfType(int attr_type,
+ size_t attr_size,
+ absl::string_view key) {
+ // Add the attribute with a dummy value. Since this is a known attribute, it
+ // can't fail.
+ RTC_DCHECK(attr_size <= kStunMessageIntegritySize);
+ auto msg_integrity_attr_ptr = std::make_unique<StunByteStringAttribute>(
+ attr_type, std::string(attr_size, '0'));
+ auto* msg_integrity_attr = msg_integrity_attr_ptr.get();
+ AddAttribute(std::move(msg_integrity_attr_ptr));
+
+ // Calculate the HMAC for the message.
+ ByteBufferWriter buf;
+ if (!Write(&buf))
+ return false;
+
+ int msg_len_for_hmac = static_cast<int>(
+ buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length());
+ char hmac[kStunMessageIntegritySize];
+ size_t ret =
+ rtc::ComputeHmac(rtc::DIGEST_SHA_1, key.data(), key.size(), buf.Data(),
+ msg_len_for_hmac, hmac, sizeof(hmac));
+ RTC_DCHECK(ret == sizeof(hmac));
+ if (ret != sizeof(hmac)) {
+ RTC_LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity "
+ "has dummy value.";
+ return false;
+ }
+
+ // Insert correct HMAC into the attribute.
+ msg_integrity_attr->CopyBytes(hmac, attr_size);
+ password_ = std::string(key);
+ integrity_ = IntegrityStatus::kIntegrityOk;
+ return true;
+}
+
+// Verifies a message is in fact a STUN message, by performing the checks
+// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
+// in section 15.5.
+bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
+ // Check the message length.
+ size_t fingerprint_attr_size =
+ kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
+ if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
+ return false;
+
+ // Skip the rest if the magic cookie isn't present.
+ const char* magic_cookie =
+ data + kStunTransactionIdOffset - kStunMagicCookieLength;
+ if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
+ return false;
+
+ // Check the fingerprint type and length.
+ const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
+ if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
+ rtc::GetBE16(fingerprint_attr_data + sizeof(uint16_t)) !=
+ StunUInt32Attribute::SIZE)
+ return false;
+
+ // Check the fingerprint value.
+ uint32_t fingerprint =
+ rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
+ return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
+ rtc::ComputeCrc32(data, size - fingerprint_attr_size));
+}
+
+// static
+std::string StunMessage::GenerateTransactionId() {
+ return rtc::CreateRandomString(kStunTransactionIdLength);
+}
+
+bool StunMessage::IsStunMethod(rtc::ArrayView<int> methods,
+ const char* data,
+ size_t size) {
+ // Check the message length.
+ if (size % 4 != 0 || size < kStunHeaderSize)
+ return false;
+
+ // Skip the rest if the magic cookie isn't present.
+ const char* magic_cookie =
+ data + kStunTransactionIdOffset - kStunMagicCookieLength;
+ if (rtc::GetBE32(magic_cookie) != kStunMagicCookie)
+ return false;
+
+ int method = rtc::GetBE16(data);
+ for (int m : methods) {
+ if (m == method) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool StunMessage::AddFingerprint() {
+ // Add the attribute with a dummy value. Since this is a known attribute,
+ // it can't fail.
+ auto fingerprint_attr_ptr =
+ std::make_unique<StunUInt32Attribute>(STUN_ATTR_FINGERPRINT, 0);
+ auto* fingerprint_attr = fingerprint_attr_ptr.get();
+ AddAttribute(std::move(fingerprint_attr_ptr));
+
+ // Calculate the CRC-32 for the message and insert it.
+ ByteBufferWriter buf;
+ if (!Write(&buf))
+ return false;
+
+ int msg_len_for_crc32 = static_cast<int>(
+ buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
+ uint32_t c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32);
+
+ // Insert the correct CRC-32, XORed with a constant, into the attribute.
+ fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
+ return true;
+}
+
+bool StunMessage::Read(ByteBufferReader* buf) {
+ // Keep a copy of the buffer data around for later verification.
+ buffer_.assign(buf->Data(), buf->Length());
+
+ if (!buf->ReadUInt16(&type_)) {
+ return false;
+ }
+
+ if (type_ & 0x8000) {
+ // RTP and RTCP set the MSB of first byte, since first two bits are version,
+ // and version is always 2 (10). If set, this is not a STUN packet.
+ return false;
+ }
+
+ if (!buf->ReadUInt16(&length_)) {
+ return false;
+ }
+
+ std::string magic_cookie;
+ if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) {
+ return false;
+ }
+
+ std::string transaction_id;
+ if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) {
+ return false;
+ }
+
+ uint32_t magic_cookie_int;
+ static_assert(sizeof(magic_cookie_int) == kStunMagicCookieLength,
+ "Integer size mismatch: magic_cookie_int and kStunMagicCookie");
+ std::memcpy(&magic_cookie_int, magic_cookie.data(), sizeof(magic_cookie_int));
+ if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) {
+ // If magic cookie is invalid it means that the peer implements
+ // RFC3489 instead of RFC5389.
+ transaction_id.insert(0, magic_cookie);
+ }
+ RTC_DCHECK(IsValidTransactionId(transaction_id));
+ transaction_id_ = transaction_id;
+ reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
+
+ if (length_ != buf->Length()) {
+ return false;
+ }
+
+ attrs_.resize(0);
+
+ size_t rest = buf->Length() - length_;
+ while (buf->Length() > rest) {
+ uint16_t attr_type, attr_length;
+ if (!buf->ReadUInt16(&attr_type))
+ return false;
+ if (!buf->ReadUInt16(&attr_length))
+ return false;
+
+ std::unique_ptr<StunAttribute> attr(
+ CreateAttribute(attr_type, attr_length));
+ if (!attr) {
+ // Skip any unknown or malformed attributes.
+ if ((attr_length % 4) != 0) {
+ attr_length += (4 - (attr_length % 4));
+ }
+ if (!buf->Consume(attr_length)) {
+ return false;
+ }
+ } else {
+ if (!attr->Read(buf)) {
+ return false;
+ }
+ attrs_.push_back(std::move(attr));
+ }
+ }
+
+ RTC_DCHECK(buf->Length() == rest);
+ return true;
+}
+
+bool StunMessage::Write(ByteBufferWriter* buf) const {
+ buf->WriteUInt16(type_);
+ buf->WriteUInt16(length_);
+ if (!IsLegacy())
+ buf->WriteUInt32(stun_magic_cookie_);
+ buf->WriteString(transaction_id_);
+
+ for (const auto& attr : attrs_) {
+ buf->WriteUInt16(attr->type());
+ buf->WriteUInt16(static_cast<uint16_t>(attr->length()));
+ if (!attr->Write(buf)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+StunMessage* StunMessage::CreateNew() const {
+ return new StunMessage();
+}
+
+void StunMessage::SetStunMagicCookie(uint32_t val) {
+ stun_magic_cookie_ = val;
+}
+
+void StunMessage::SetTransactionIdForTesting(absl::string_view transaction_id) {
+ RTC_DCHECK(IsValidTransactionId(transaction_id));
+ transaction_id_ = std::string(transaction_id);
+ reduced_transaction_id_ = ReduceTransactionId(transaction_id_);
+}
+
+StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
+ switch (type) {
+ case STUN_ATTR_MAPPED_ADDRESS:
+ return STUN_VALUE_ADDRESS;
+ case STUN_ATTR_USERNAME:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_MESSAGE_INTEGRITY:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_ERROR_CODE:
+ return STUN_VALUE_ERROR_CODE;
+ case STUN_ATTR_UNKNOWN_ATTRIBUTES:
+ return STUN_VALUE_UINT16_LIST;
+ case STUN_ATTR_REALM:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_NONCE:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_XOR_MAPPED_ADDRESS:
+ return STUN_VALUE_XOR_ADDRESS;
+ case STUN_ATTR_SOFTWARE:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_ALTERNATE_SERVER:
+ return STUN_VALUE_ADDRESS;
+ case STUN_ATTR_FINGERPRINT:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_RETRANSMIT_COUNT:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_GOOG_MISC_INFO:
+ return STUN_VALUE_UINT16_LIST;
+ default:
+ return STUN_VALUE_UNKNOWN;
+ }
+}
+
+StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
+ StunAttributeValueType value_type = GetAttributeValueType(type);
+ if (value_type != STUN_VALUE_UNKNOWN) {
+ return StunAttribute::Create(value_type, type,
+ static_cast<uint16_t>(length), this);
+ } else if (DesignatedExpertRange(type)) {
+ // Read unknown attributes as STUN_VALUE_BYTE_STRING
+ return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
+ static_cast<uint16_t>(length), this);
+ } else {
+ return NULL;
+ }
+}
+
+const StunAttribute* StunMessage::GetAttribute(int type) const {
+ for (const auto& attr : attrs_) {
+ if (attr->type() == type) {
+ return attr.get();
+ }
+ }
+ return NULL;
+}
+
+bool StunMessage::IsValidTransactionId(absl::string_view transaction_id) {
+ return transaction_id.size() == kStunTransactionIdLength ||
+ transaction_id.size() == kStunLegacyTransactionIdLength;
+}
+
+bool StunMessage::EqualAttributes(
+ const StunMessage* other,
+ std::function<bool(int type)> attribute_type_mask) const {
+ RTC_DCHECK(other != nullptr);
+ rtc::ByteBufferWriter tmp_buffer_ptr1;
+ rtc::ByteBufferWriter tmp_buffer_ptr2;
+ for (const auto& attr : attrs_) {
+ if (attribute_type_mask(attr->type())) {
+ const StunAttribute* other_attr = other->GetAttribute(attr->type());
+ if (other_attr == nullptr) {
+ return false;
+ }
+ tmp_buffer_ptr1.Clear();
+ tmp_buffer_ptr2.Clear();
+ attr->Write(&tmp_buffer_ptr1);
+ other_attr->Write(&tmp_buffer_ptr2);
+ if (tmp_buffer_ptr1.Length() != tmp_buffer_ptr2.Length()) {
+ return false;
+ }
+ if (memcmp(tmp_buffer_ptr1.Data(), tmp_buffer_ptr2.Data(),
+ tmp_buffer_ptr1.Length()) != 0) {
+ return false;
+ }
+ }
+ }
+
+ for (const auto& attr : other->attrs_) {
+ if (attribute_type_mask(attr->type())) {
+ const StunAttribute* own_attr = GetAttribute(attr->type());
+ if (own_attr == nullptr) {
+ return false;
+ }
+ // we have already compared all values...
+ }
+ }
+ return true;
+}
+
+// StunAttribute
+
+StunAttribute::StunAttribute(uint16_t type, uint16_t length)
+ : type_(type), length_(length) {}
+
+void StunAttribute::ConsumePadding(ByteBufferReader* buf) const {
+ int remainder = length_ % 4;
+ if (remainder > 0) {
+ buf->Consume(4 - remainder);
+ }
+}
+
+void StunAttribute::WritePadding(ByteBufferWriter* buf) const {
+ int remainder = length_ % 4;
+ if (remainder > 0) {
+ char zeroes[4] = {0};
+ buf->WriteBytes(zeroes, 4 - remainder);
+ }
+}
+
+StunAttribute* StunAttribute::Create(StunAttributeValueType value_type,
+ uint16_t type,
+ uint16_t length,
+ StunMessage* owner) {
+ switch (value_type) {
+ case STUN_VALUE_ADDRESS:
+ return new StunAddressAttribute(type, length);
+ case STUN_VALUE_XOR_ADDRESS:
+ return new StunXorAddressAttribute(type, length, owner);
+ case STUN_VALUE_UINT32:
+ return new StunUInt32Attribute(type);
+ case STUN_VALUE_UINT64:
+ return new StunUInt64Attribute(type);
+ case STUN_VALUE_BYTE_STRING:
+ return new StunByteStringAttribute(type, length);
+ case STUN_VALUE_ERROR_CODE:
+ return new StunErrorCodeAttribute(type, length);
+ case STUN_VALUE_UINT16_LIST:
+ return new StunUInt16ListAttribute(type, length);
+ default:
+ return NULL;
+ }
+}
+
+std::unique_ptr<StunAddressAttribute> StunAttribute::CreateAddress(
+ uint16_t type) {
+ return std::make_unique<StunAddressAttribute>(type, 0);
+}
+
+std::unique_ptr<StunXorAddressAttribute> StunAttribute::CreateXorAddress(
+ uint16_t type) {
+ return std::make_unique<StunXorAddressAttribute>(type, 0, nullptr);
+}
+
+std::unique_ptr<StunUInt64Attribute> StunAttribute::CreateUInt64(
+ uint16_t type) {
+ return std::make_unique<StunUInt64Attribute>(type);
+}
+
+std::unique_ptr<StunUInt32Attribute> StunAttribute::CreateUInt32(
+ uint16_t type) {
+ return std::make_unique<StunUInt32Attribute>(type);
+}
+
+std::unique_ptr<StunByteStringAttribute> StunAttribute::CreateByteString(
+ uint16_t type) {
+ return std::make_unique<StunByteStringAttribute>(type, 0);
+}
+
+std::unique_ptr<StunErrorCodeAttribute> StunAttribute::CreateErrorCode() {
+ return std::make_unique<StunErrorCodeAttribute>(
+ STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE);
+}
+
+std::unique_ptr<StunUInt16ListAttribute>
+StunAttribute::CreateUInt16ListAttribute(uint16_t type) {
+ return std::make_unique<StunUInt16ListAttribute>(type, 0);
+}
+
+std::unique_ptr<StunUInt16ListAttribute>
+StunAttribute::CreateUnknownAttributes() {
+ return std::make_unique<StunUInt16ListAttribute>(STUN_ATTR_UNKNOWN_ATTRIBUTES,
+ 0);
+}
+
+StunAddressAttribute::StunAddressAttribute(uint16_t type,
+ const rtc::SocketAddress& addr)
+ : StunAttribute(type, 0) {
+ SetAddress(addr);
+}
+
+StunAddressAttribute::StunAddressAttribute(uint16_t type, uint16_t length)
+ : StunAttribute(type, length) {}
+
+StunAttributeValueType StunAddressAttribute::value_type() const {
+ return STUN_VALUE_ADDRESS;
+}
+
+bool StunAddressAttribute::Read(ByteBufferReader* buf) {
+ uint8_t dummy;
+ if (!buf->ReadUInt8(&dummy))
+ return false;
+
+ uint8_t stun_family;
+ if (!buf->ReadUInt8(&stun_family)) {
+ return false;
+ }
+ uint16_t port;
+ if (!buf->ReadUInt16(&port))
+ return false;
+ if (stun_family == STUN_ADDRESS_IPV4) {
+ in_addr v4addr;
+ if (length() != SIZE_IP4) {
+ return false;
+ }
+ if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) {
+ return false;
+ }
+ rtc::IPAddress ipaddr(v4addr);
+ SetAddress(rtc::SocketAddress(ipaddr, port));
+ } else if (stun_family == STUN_ADDRESS_IPV6) {
+ in6_addr v6addr;
+ if (length() != SIZE_IP6) {
+ return false;
+ }
+ if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) {
+ return false;
+ }
+ rtc::IPAddress ipaddr(v6addr);
+ SetAddress(rtc::SocketAddress(ipaddr, port));
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool StunAddressAttribute::Write(ByteBufferWriter* buf) const {
+ StunAddressFamily address_family = family();
+ if (address_family == STUN_ADDRESS_UNDEF) {
+ RTC_LOG(LS_ERROR) << "Error writing address attribute: unknown family.";
+ return false;
+ }
+ buf->WriteUInt8(0);
+ buf->WriteUInt8(address_family);
+ buf->WriteUInt16(address_.port());
+ switch (address_.family()) {
+ case AF_INET: {
+ in_addr v4addr = address_.ipaddr().ipv4_address();
+ buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr));
+ break;
+ }
+ case AF_INET6: {
+ in6_addr v6addr = address_.ipaddr().ipv6_address();
+ buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr));
+ break;
+ }
+ }
+ return true;
+}
+
+StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
+ const rtc::SocketAddress& addr)
+ : StunAddressAttribute(type, addr), owner_(NULL) {}
+
+StunXorAddressAttribute::StunXorAddressAttribute(uint16_t type,
+ uint16_t length,
+ StunMessage* owner)
+ : StunAddressAttribute(type, length), owner_(owner) {}
+
+StunAttributeValueType StunXorAddressAttribute::value_type() const {
+ return STUN_VALUE_XOR_ADDRESS;
+}
+
+void StunXorAddressAttribute::SetOwner(StunMessage* owner) {
+ owner_ = owner;
+}
+
+rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const {
+ if (owner_) {
+ rtc::IPAddress ip = ipaddr();
+ switch (ip.family()) {
+ case AF_INET: {
+ in_addr v4addr = ip.ipv4_address();
+ v4addr.s_addr =
+ (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie));
+ return rtc::IPAddress(v4addr);
+ }
+ case AF_INET6: {
+ in6_addr v6addr = ip.ipv6_address();
+ const std::string& transaction_id = owner_->transaction_id();
+ if (transaction_id.length() == kStunTransactionIdLength) {
+ uint32_t transactionid_as_ints[3];
+ memcpy(&transactionid_as_ints[0], transaction_id.c_str(),
+ transaction_id.length());
+ uint32_t* ip_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
+ // Transaction ID is in network byte order, but magic cookie
+ // is stored in host byte order.
+ ip_as_ints[0] =
+ (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie));
+ ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]);
+ ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]);
+ ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]);
+ return rtc::IPAddress(v6addr);
+ }
+ break;
+ }
+ }
+ }
+ // Invalid ip family or transaction ID, or missing owner.
+ // Return an AF_UNSPEC address.
+ return rtc::IPAddress();
+}
+
+bool StunXorAddressAttribute::Read(ByteBufferReader* buf) {
+ if (!StunAddressAttribute::Read(buf))
+ return false;
+ uint16_t xoredport = port() ^ (kStunMagicCookie >> 16);
+ rtc::IPAddress xored_ip = GetXoredIP();
+ SetAddress(rtc::SocketAddress(xored_ip, xoredport));
+ return true;
+}
+
+bool StunXorAddressAttribute::Write(ByteBufferWriter* buf) const {
+ StunAddressFamily address_family = family();
+ if (address_family == STUN_ADDRESS_UNDEF) {
+ RTC_LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family.";
+ return false;
+ }
+ rtc::IPAddress xored_ip = GetXoredIP();
+ if (xored_ip.family() == AF_UNSPEC) {
+ return false;
+ }
+ buf->WriteUInt8(0);
+ buf->WriteUInt8(family());
+ buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
+ switch (xored_ip.family()) {
+ case AF_INET: {
+ in_addr v4addr = xored_ip.ipv4_address();
+ buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr));
+ break;
+ }
+ case AF_INET6: {
+ in6_addr v6addr = xored_ip.ipv6_address();
+ buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr));
+ break;
+ }
+ }
+ return true;
+}
+
+StunUInt32Attribute::StunUInt32Attribute(uint16_t type, uint32_t value)
+ : StunAttribute(type, SIZE), bits_(value) {}
+
+StunUInt32Attribute::StunUInt32Attribute(uint16_t type)
+ : StunAttribute(type, SIZE), bits_(0) {}
+
+StunAttributeValueType StunUInt32Attribute::value_type() const {
+ return STUN_VALUE_UINT32;
+}
+
+bool StunUInt32Attribute::GetBit(size_t index) const {
+ RTC_DCHECK(index < 32);
+ return static_cast<bool>((bits_ >> index) & 0x1);
+}
+
+void StunUInt32Attribute::SetBit(size_t index, bool value) {
+ RTC_DCHECK(index < 32);
+ bits_ &= ~(1 << index);
+ bits_ |= value ? (1 << index) : 0;
+}
+
+bool StunUInt32Attribute::Read(ByteBufferReader* buf) {
+ if (length() != SIZE || !buf->ReadUInt32(&bits_))
+ return false;
+ return true;
+}
+
+bool StunUInt32Attribute::Write(ByteBufferWriter* buf) const {
+ buf->WriteUInt32(bits_);
+ return true;
+}
+
+StunUInt64Attribute::StunUInt64Attribute(uint16_t type, uint64_t value)
+ : StunAttribute(type, SIZE), bits_(value) {}
+
+StunUInt64Attribute::StunUInt64Attribute(uint16_t type)
+ : StunAttribute(type, SIZE), bits_(0) {}
+
+StunAttributeValueType StunUInt64Attribute::value_type() const {
+ return STUN_VALUE_UINT64;
+}
+
+bool StunUInt64Attribute::Read(ByteBufferReader* buf) {
+ if (length() != SIZE || !buf->ReadUInt64(&bits_))
+ return false;
+ return true;
+}
+
+bool StunUInt64Attribute::Write(ByteBufferWriter* buf) const {
+ buf->WriteUInt64(bits_);
+ return true;
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16_t type)
+ : StunAttribute(type, 0), bytes_(NULL) {}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
+ absl::string_view str)
+ : StunAttribute(type, 0), bytes_(NULL) {
+ CopyBytes(str);
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16_t type,
+ const void* bytes,
+ size_t length)
+ : StunAttribute(type, 0), bytes_(NULL) {
+ CopyBytes(bytes, length);
+}
+
+StunByteStringAttribute::StunByteStringAttribute(uint16_t type, uint16_t length)
+ : StunAttribute(type, length), bytes_(NULL) {}
+
+StunByteStringAttribute::~StunByteStringAttribute() {
+ delete[] bytes_;
+}
+
+StunAttributeValueType StunByteStringAttribute::value_type() const {
+ return STUN_VALUE_BYTE_STRING;
+}
+
+void StunByteStringAttribute::CopyBytes(absl::string_view bytes) {
+ char* new_bytes = new char[bytes.size()];
+ memcpy(new_bytes, bytes.data(), bytes.size());
+ SetBytes(new_bytes, bytes.size());
+}
+
+void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
+ char* new_bytes = new char[length];
+ memcpy(new_bytes, bytes, length);
+ SetBytes(new_bytes, length);
+}
+
+uint8_t StunByteStringAttribute::GetByte(size_t index) const {
+ RTC_DCHECK(bytes_ != NULL);
+ RTC_DCHECK(index < length());
+ return static_cast<uint8_t>(bytes_[index]);
+}
+
+void StunByteStringAttribute::SetByte(size_t index, uint8_t value) {
+ RTC_DCHECK(bytes_ != NULL);
+ RTC_DCHECK(index < length());
+ bytes_[index] = value;
+}
+
+bool StunByteStringAttribute::Read(ByteBufferReader* buf) {
+ bytes_ = new char[length()];
+ if (!buf->ReadBytes(bytes_, length())) {
+ return false;
+ }
+
+ ConsumePadding(buf);
+ return true;
+}
+
+bool StunByteStringAttribute::Write(ByteBufferWriter* buf) const {
+ // Check that length is legal according to specs
+ if (!LengthValid(type(), length())) {
+ return false;
+ }
+ buf->WriteBytes(bytes_, length());
+ WritePadding(buf);
+ return true;
+}
+
+void StunByteStringAttribute::SetBytes(char* bytes, size_t length) {
+ delete[] bytes_;
+ bytes_ = bytes;
+ SetLength(static_cast<uint16_t>(length));
+}
+
+const uint16_t StunErrorCodeAttribute::MIN_SIZE = 4;
+
+StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type,
+ int code,
+ const std::string& reason)
+ : StunAttribute(type, 0) {
+ SetCode(code);
+ SetReason(reason);
+}
+
+StunErrorCodeAttribute::StunErrorCodeAttribute(uint16_t type, uint16_t length)
+ : StunAttribute(type, length), class_(0), number_(0) {}
+
+StunErrorCodeAttribute::~StunErrorCodeAttribute() {}
+
+StunAttributeValueType StunErrorCodeAttribute::value_type() const {
+ return STUN_VALUE_ERROR_CODE;
+}
+
+int StunErrorCodeAttribute::code() const {
+ return class_ * 100 + number_;
+}
+
+void StunErrorCodeAttribute::SetCode(int code) {
+ class_ = static_cast<uint8_t>(code / 100);
+ number_ = static_cast<uint8_t>(code % 100);
+}
+
+void StunErrorCodeAttribute::SetReason(const std::string& reason) {
+ SetLength(MIN_SIZE + static_cast<uint16_t>(reason.size()));
+ reason_ = reason;
+}
+
+bool StunErrorCodeAttribute::Read(ByteBufferReader* buf) {
+ uint32_t val;
+ if (length() < MIN_SIZE || !buf->ReadUInt32(&val))
+ return false;
+
+ if ((val >> 11) != 0)
+ RTC_LOG(LS_ERROR) << "error-code bits not zero";
+
+ class_ = ((val >> 8) & 0x7);
+ number_ = (val & 0xff);
+
+ if (!buf->ReadString(&reason_, length() - 4))
+ return false;
+
+ ConsumePadding(buf);
+ return true;
+}
+
+bool StunErrorCodeAttribute::Write(ByteBufferWriter* buf) const {
+ buf->WriteUInt32(class_ << 8 | number_);
+ buf->WriteString(reason_);
+ WritePadding(buf);
+ return true;
+}
+
+StunUInt16ListAttribute::StunUInt16ListAttribute(uint16_t type, uint16_t length)
+ : StunAttribute(type, length) {
+ attr_types_ = new std::vector<uint16_t>();
+}
+
+StunUInt16ListAttribute::~StunUInt16ListAttribute() {
+ delete attr_types_;
+}
+
+StunAttributeValueType StunUInt16ListAttribute::value_type() const {
+ return STUN_VALUE_UINT16_LIST;
+}
+
+size_t StunUInt16ListAttribute::Size() const {
+ return attr_types_->size();
+}
+
+uint16_t StunUInt16ListAttribute::GetType(int index) const {
+ return (*attr_types_)[index];
+}
+
+void StunUInt16ListAttribute::SetType(int index, uint16_t value) {
+ (*attr_types_)[index] = value;
+}
+
+void StunUInt16ListAttribute::AddType(uint16_t value) {
+ attr_types_->push_back(value);
+ SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
+}
+
+void StunUInt16ListAttribute::AddTypeAtIndex(uint16_t index, uint16_t value) {
+ if (attr_types_->size() < static_cast<size_t>(index + 1)) {
+ attr_types_->resize(index + 1);
+ }
+ (*attr_types_)[index] = value;
+ SetLength(static_cast<uint16_t>(attr_types_->size() * 2));
+}
+
+bool StunUInt16ListAttribute::Read(ByteBufferReader* buf) {
+ if (length() % 2) {
+ return false;
+ }
+
+ for (size_t i = 0; i < length() / 2; i++) {
+ uint16_t attr;
+ if (!buf->ReadUInt16(&attr))
+ return false;
+ attr_types_->push_back(attr);
+ }
+ // Padding of these attributes is done in RFC 5389 style. This is
+ // slightly different from RFC3489, but it shouldn't be important.
+ // RFC3489 pads out to a 32 bit boundary by duplicating one of the
+ // entries in the list (not necessarily the last one - it's unspecified).
+ // RFC5389 pads on the end, and the bytes are always ignored.
+ ConsumePadding(buf);
+ return true;
+}
+
+bool StunUInt16ListAttribute::Write(ByteBufferWriter* buf) const {
+ for (size_t i = 0; i < attr_types_->size(); ++i) {
+ buf->WriteUInt16((*attr_types_)[i]);
+ }
+ WritePadding(buf);
+ return true;
+}
+
+std::string StunMethodToString(int msg_type) {
+ switch (msg_type) {
+ case STUN_BINDING_REQUEST:
+ return "STUN BINDING request";
+ case STUN_BINDING_INDICATION:
+ return "STUN BINDING indication";
+ case STUN_BINDING_RESPONSE:
+ return "STUN BINDING response";
+ case STUN_BINDING_ERROR_RESPONSE:
+ return "STUN BINDING error response";
+ case GOOG_PING_REQUEST:
+ return "GOOG PING request";
+ case GOOG_PING_RESPONSE:
+ return "GOOG PING response";
+ case GOOG_PING_ERROR_RESPONSE:
+ return "GOOG PING error response";
+ case STUN_ALLOCATE_REQUEST:
+ return "TURN ALLOCATE request";
+ case STUN_ALLOCATE_RESPONSE:
+ return "TURN ALLOCATE response";
+ case STUN_ALLOCATE_ERROR_RESPONSE:
+ return "TURN ALLOCATE error response";
+ case TURN_REFRESH_REQUEST:
+ return "TURN REFRESH request";
+ case TURN_REFRESH_RESPONSE:
+ return "TURN REFRESH response";
+ case TURN_REFRESH_ERROR_RESPONSE:
+ return "TURN REFRESH error response";
+ case TURN_SEND_INDICATION:
+ return "TURN SEND INDICATION";
+ case TURN_DATA_INDICATION:
+ return "TURN DATA INDICATION";
+ case TURN_CREATE_PERMISSION_REQUEST:
+ return "TURN CREATE PERMISSION request";
+ case TURN_CREATE_PERMISSION_RESPONSE:
+ return "TURN CREATE PERMISSION response";
+ case TURN_CREATE_PERMISSION_ERROR_RESPONSE:
+ return "TURN CREATE PERMISSION error response";
+ case TURN_CHANNEL_BIND_REQUEST:
+ return "TURN CHANNEL BIND request";
+ case TURN_CHANNEL_BIND_RESPONSE:
+ return "TURN CHANNEL BIND response";
+ case TURN_CHANNEL_BIND_ERROR_RESPONSE:
+ return "TURN CHANNEL BIND error response";
+ default:
+ return "UNKNOWN<" + std::to_string(msg_type) + ">";
+ }
+}
+
+int GetStunSuccessResponseType(int req_type) {
+ return IsStunRequestType(req_type) ? (req_type | 0x100) : -1;
+}
+
+int GetStunErrorResponseType(int req_type) {
+ return IsStunRequestType(req_type) ? (req_type | 0x110) : -1;
+}
+
+bool IsStunRequestType(int msg_type) {
+ return ((msg_type & kStunTypeMask) == 0x000);
+}
+
+bool IsStunIndicationType(int msg_type) {
+ return ((msg_type & kStunTypeMask) == 0x010);
+}
+
+bool IsStunSuccessResponseType(int msg_type) {
+ return ((msg_type & kStunTypeMask) == 0x100);
+}
+
+bool IsStunErrorResponseType(int msg_type) {
+ return ((msg_type & kStunTypeMask) == 0x110);
+}
+
+bool ComputeStunCredentialHash(const std::string& username,
+ const std::string& realm,
+ const std::string& password,
+ std::string* hash) {
+ // http://tools.ietf.org/html/rfc5389#section-15.4
+ // long-term credentials will be calculated using the key and key is
+ // key = MD5(username ":" realm ":" SASLprep(password))
+ std::string input = username;
+ input += ':';
+ input += realm;
+ input += ':';
+ input += password;
+
+ char digest[rtc::MessageDigest::kMaxSize];
+ size_t size = rtc::ComputeDigest(rtc::DIGEST_MD5, input.c_str(), input.size(),
+ digest, sizeof(digest));
+ if (size == 0) {
+ return false;
+ }
+
+ *hash = std::string(digest, size);
+ return true;
+}
+
+std::unique_ptr<StunAttribute> CopyStunAttribute(
+ const StunAttribute& attribute,
+ rtc::ByteBufferWriter* tmp_buffer_ptr) {
+ ByteBufferWriter tmpBuffer;
+ if (tmp_buffer_ptr == nullptr) {
+ tmp_buffer_ptr = &tmpBuffer;
+ }
+
+ std::unique_ptr<StunAttribute> copy(StunAttribute::Create(
+ attribute.value_type(), attribute.type(),
+ static_cast<uint16_t>(attribute.length()), nullptr));
+
+ if (!copy) {
+ return nullptr;
+ }
+ tmp_buffer_ptr->Clear();
+ if (!attribute.Write(tmp_buffer_ptr)) {
+ return nullptr;
+ }
+ rtc::ByteBufferReader reader(*tmp_buffer_ptr);
+ if (!copy->Read(&reader)) {
+ return nullptr;
+ }
+
+ return copy;
+}
+
+StunAttributeValueType RelayMessage::GetAttributeValueType(int type) const {
+ switch (type) {
+ case STUN_ATTR_LIFETIME:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_MAGIC_COOKIE:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_BANDWIDTH:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_DESTINATION_ADDRESS:
+ return STUN_VALUE_ADDRESS;
+ case STUN_ATTR_SOURCE_ADDRESS2:
+ return STUN_VALUE_ADDRESS;
+ case STUN_ATTR_DATA:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_OPTIONS:
+ return STUN_VALUE_UINT32;
+ default:
+ return StunMessage::GetAttributeValueType(type);
+ }
+}
+
+StunMessage* RelayMessage::CreateNew() const {
+ return new RelayMessage();
+}
+
+StunAttributeValueType TurnMessage::GetAttributeValueType(int type) const {
+ switch (type) {
+ case STUN_ATTR_CHANNEL_NUMBER:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_TURN_LIFETIME:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_XOR_PEER_ADDRESS:
+ return STUN_VALUE_XOR_ADDRESS;
+ case STUN_ATTR_DATA:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_XOR_RELAYED_ADDRESS:
+ return STUN_VALUE_XOR_ADDRESS;
+ case STUN_ATTR_EVEN_PORT:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_REQUESTED_TRANSPORT:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_DONT_FRAGMENT:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_RESERVATION_TOKEN:
+ return STUN_VALUE_BYTE_STRING;
+ default:
+ return StunMessage::GetAttributeValueType(type);
+ }
+}
+
+StunMessage* TurnMessage::CreateNew() const {
+ return new TurnMessage();
+}
+
+StunAttributeValueType IceMessage::GetAttributeValueType(int type) const {
+ switch (type) {
+ case STUN_ATTR_PRIORITY:
+ case STUN_ATTR_GOOG_NETWORK_INFO:
+ case STUN_ATTR_NOMINATION:
+ return STUN_VALUE_UINT32;
+ case STUN_ATTR_USE_CANDIDATE:
+ return STUN_VALUE_BYTE_STRING;
+ case STUN_ATTR_ICE_CONTROLLED:
+ return STUN_VALUE_UINT64;
+ case STUN_ATTR_ICE_CONTROLLING:
+ return STUN_VALUE_UINT64;
+ default:
+ return StunMessage::GetAttributeValueType(type);
+ }
+}
+
+StunMessage* IceMessage::CreateNew() const {
+ return new IceMessage();
+}
+
+std::unique_ptr<StunMessage> StunMessage::Clone() const {
+ std::unique_ptr<StunMessage> copy(CreateNew());
+ if (!copy) {
+ return nullptr;
+ }
+ rtc::ByteBufferWriter buf;
+ if (!Write(&buf)) {
+ return nullptr;
+ }
+ rtc::ByteBufferReader reader(buf);
+ if (!copy->Read(&reader)) {
+ return nullptr;
+ }
+ return copy;
+}
+
+} // namespace cricket
diff --git a/third_party/libwebrtc/api/transport/stun.h b/third_party/libwebrtc/api/transport/stun.h
new file mode 100644
index 0000000000..c2c9ad4b9c
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/stun.h
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_STUN_H_
+#define API_TRANSPORT_STUN_H_
+
+// This file contains classes for dealing with the STUN protocol, as specified
+// in RFC 5389, and its descendants.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "rtc_base/byte_buffer.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/socket_address.h"
+
+namespace cricket {
+
+// These are the types of STUN messages defined in RFC 5389.
+enum StunMessageType : uint16_t {
+ STUN_INVALID_MESSAGE_TYPE = 0x0000,
+ STUN_BINDING_REQUEST = 0x0001,
+ STUN_BINDING_INDICATION = 0x0011,
+ STUN_BINDING_RESPONSE = 0x0101,
+ STUN_BINDING_ERROR_RESPONSE = 0x0111,
+
+ // Method 0x80, GOOG-PING is a variant of STUN BINDING
+ // that is sent instead of a STUN BINDING if the binding
+ // was identical to the one before.
+ GOOG_PING_REQUEST = 0x200,
+ GOOG_PING_RESPONSE = 0x300,
+ GOOG_PING_ERROR_RESPONSE = 0x310,
+};
+
+// These are all known STUN attributes, defined in RFC 5389 and elsewhere.
+// Next to each is the name of the class (T is StunTAttribute) that implements
+// that type.
+// RETRANSMIT_COUNT is the number of outstanding pings without a response at
+// the time the packet is generated.
+enum StunAttributeType {
+ STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address
+ STUN_ATTR_USERNAME = 0x0006, // ByteString
+ STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes
+ STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode
+ STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List
+ STUN_ATTR_REALM = 0x0014, // ByteString
+ STUN_ATTR_NONCE = 0x0015, // ByteString
+ STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress
+ STUN_ATTR_SOFTWARE = 0x8022, // ByteString
+ STUN_ATTR_ALTERNATE_SERVER = 0x8023, // Address
+ STUN_ATTR_FINGERPRINT = 0x8028, // UInt32
+ STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32
+};
+
+// These are the types of the values associated with the attributes above.
+// This allows us to perform some basic validation when reading or adding
+// attributes. Note that these values are for our own use, and not defined in
+// RFC 5389.
+enum StunAttributeValueType {
+ STUN_VALUE_UNKNOWN = 0,
+ STUN_VALUE_ADDRESS = 1,
+ STUN_VALUE_XOR_ADDRESS = 2,
+ STUN_VALUE_UINT32 = 3,
+ STUN_VALUE_UINT64 = 4,
+ STUN_VALUE_BYTE_STRING = 5,
+ STUN_VALUE_ERROR_CODE = 6,
+ STUN_VALUE_UINT16_LIST = 7
+};
+
+// These are the types of STUN addresses defined in RFC 5389.
+enum StunAddressFamily {
+ // NB: UNDEF is not part of the STUN spec.
+ STUN_ADDRESS_UNDEF = 0,
+ STUN_ADDRESS_IPV4 = 1,
+ STUN_ADDRESS_IPV6 = 2
+};
+
+// These are the types of STUN error codes defined in RFC 5389.
+enum StunErrorCode {
+ STUN_ERROR_TRY_ALTERNATE = 300,
+ STUN_ERROR_BAD_REQUEST = 400,
+ STUN_ERROR_UNAUTHORIZED = 401,
+ STUN_ERROR_UNKNOWN_ATTRIBUTE = 420,
+ STUN_ERROR_STALE_NONCE = 438,
+ STUN_ERROR_SERVER_ERROR = 500,
+ STUN_ERROR_GLOBAL_FAILURE = 600
+};
+
+// Strings for the error codes above.
+extern const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[];
+extern const char STUN_ERROR_REASON_BAD_REQUEST[];
+extern const char STUN_ERROR_REASON_UNAUTHORIZED[];
+extern const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[];
+extern const char STUN_ERROR_REASON_STALE_NONCE[];
+extern const char STUN_ERROR_REASON_SERVER_ERROR[];
+
+// The mask used to determine whether a STUN message is a request/response etc.
+const uint32_t kStunTypeMask = 0x0110;
+
+// STUN Attribute header length.
+const size_t kStunAttributeHeaderSize = 4;
+
+// Following values correspond to RFC5389.
+const size_t kStunHeaderSize = 20;
+const size_t kStunTransactionIdOffset = 8;
+const size_t kStunTransactionIdLength = 12;
+const uint32_t kStunMagicCookie = 0x2112A442;
+constexpr size_t kStunMagicCookieLength = sizeof(kStunMagicCookie);
+
+// Following value corresponds to an earlier version of STUN from
+// RFC3489.
+const size_t kStunLegacyTransactionIdLength = 16;
+
+// STUN Message Integrity HMAC length.
+const size_t kStunMessageIntegritySize = 20;
+// Size of STUN_ATTR_MESSAGE_INTEGRITY_32
+const size_t kStunMessageIntegrity32Size = 4;
+
+class StunAddressAttribute;
+class StunAttribute;
+class StunByteStringAttribute;
+class StunErrorCodeAttribute;
+class StunUInt16ListAttribute;
+class StunUInt32Attribute;
+class StunUInt64Attribute;
+class StunXorAddressAttribute;
+
+// Records a complete STUN/TURN message. Each message consists of a type and
+// any number of attributes. Each attribute is parsed into an instance of an
+// appropriate class (see above). The Get* methods will return instances of
+// that attribute class.
+class StunMessage {
+ public:
+ // Constructs a StunMessage with an invalid type and empty, legacy length
+ // (16 bytes, RFC3489) transaction id.
+ StunMessage();
+
+ // Construct a `StunMessage` with a specific type and generate a new
+ // 12 byte transaction id (RFC5389).
+ explicit StunMessage(uint16_t type);
+
+ StunMessage(uint16_t type, absl::string_view transaction_id);
+
+ virtual ~StunMessage();
+
+ // The verification status of the message. This is checked on parsing,
+ // or set by AddMessageIntegrity.
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class IntegrityStatus {
+ kNotSet = 0,
+ kNoIntegrity = 1, // Message-integrity attribute missing
+ kIntegrityOk = 2, // Message-integrity checked OK
+ kIntegrityBad = 3, // Message-integrity verification failed
+ kMaxValue = kIntegrityBad,
+ };
+
+ int type() const { return type_; }
+ size_t length() const { return length_; }
+ const std::string& transaction_id() const { return transaction_id_; }
+ uint32_t reduced_transaction_id() const { return reduced_transaction_id_; }
+
+ // Returns true if the message confirms to RFC3489 rather than
+ // RFC5389. The main difference between the two versions of the STUN
+ // protocol is the presence of the magic cookie and different length
+ // of transaction ID. For outgoing packets the version of the protocol
+ // is determined by the lengths of the transaction ID.
+ bool IsLegacy() const;
+
+ [[deprecated]] void SetType(int type) { type_ = static_cast<uint16_t>(type); }
+ [[deprecated]] bool SetTransactionID(absl::string_view transaction_id) {
+ if (!IsValidTransactionId(transaction_id))
+ return false;
+ SetTransactionIdForTesting(transaction_id);
+ return true;
+ }
+
+ // Get a list of all of the attribute types in the "comprehension required"
+ // range that were not recognized.
+ std::vector<uint16_t> GetNonComprehendedAttributes() const;
+
+ // Gets the desired attribute value, or NULL if no such attribute type exists.
+ const StunAddressAttribute* GetAddress(int type) const;
+ const StunUInt32Attribute* GetUInt32(int type) const;
+ const StunUInt64Attribute* GetUInt64(int type) const;
+ const StunByteStringAttribute* GetByteString(int type) const;
+ const StunUInt16ListAttribute* GetUInt16List(int type) const;
+
+ // Gets these specific attribute values.
+ const StunErrorCodeAttribute* GetErrorCode() const;
+ // Returns the code inside the error code attribute, if present, and
+ // STUN_ERROR_GLOBAL_FAILURE otherwise.
+ int GetErrorCodeValue() const;
+ const StunUInt16ListAttribute* GetUnknownAttributes() const;
+
+ // Takes ownership of the specified attribute and adds it to the message.
+ void AddAttribute(std::unique_ptr<StunAttribute> attr);
+
+ // Remove the last occurrence of an attribute.
+ std::unique_ptr<StunAttribute> RemoveAttribute(int type);
+
+ // Remote all attributes and releases them.
+ void ClearAttributes();
+
+ // Validates that a STUN message has a correct MESSAGE-INTEGRITY value.
+ // This uses the buffered raw-format message stored by Read().
+ IntegrityStatus ValidateMessageIntegrity(const std::string& password);
+
+ // Revalidates the STUN message with (possibly) a new password.
+ // Indicates that calling logic needs review - probably previous call
+ // was checking with the wrong password.
+ IntegrityStatus RevalidateMessageIntegrity(const std::string& password);
+
+ // Returns the current integrity status of the message.
+ IntegrityStatus integrity() const { return integrity_; }
+
+ // Shortcut for checking if integrity is verified.
+ bool IntegrityOk() const {
+ return integrity_ == IntegrityStatus::kIntegrityOk;
+ }
+
+ // Returns the password attribute used to set or check the integrity.
+ // Can only be called after adding or checking the integrity.
+ std::string password() const {
+ RTC_DCHECK(integrity_ != IntegrityStatus::kNotSet);
+ return password_;
+ }
+
+ // Adds a MESSAGE-INTEGRITY attribute that is valid for the current message.
+ bool AddMessageIntegrity(absl::string_view password);
+
+ // Adds a STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32 attribute that is valid for the
+ // current message.
+ bool AddMessageIntegrity32(absl::string_view password);
+
+ // Verify that a buffer has stun magic cookie and one of the specified
+ // methods. Note that it does not check for the existance of FINGERPRINT.
+ static bool IsStunMethod(rtc::ArrayView<int> methods,
+ const char* data,
+ size_t size);
+
+ // Verifies that a given buffer is STUN by checking for a correct FINGERPRINT.
+ static bool ValidateFingerprint(const char* data, size_t size);
+
+ // Generates a new 12 byte (RFC5389) transaction id.
+ static std::string GenerateTransactionId();
+
+ // Adds a FINGERPRINT attribute that is valid for the current message.
+ bool AddFingerprint();
+
+ // Parses the STUN packet in the given buffer and records it here. The
+ // return value indicates whether this was successful.
+ bool Read(rtc::ByteBufferReader* buf);
+
+ // Writes this object into a STUN packet. The return value indicates whether
+ // this was successful.
+ bool Write(rtc::ByteBufferWriter* buf) const;
+
+ // Creates an empty message. Overridable by derived classes.
+ virtual StunMessage* CreateNew() const;
+
+ // Modify the stun magic cookie used for this STUN message.
+ // This is used for testing.
+ [[deprecated]] void SetStunMagicCookie(uint32_t val);
+
+ // Change the internal transaction id. Used only for testing.
+ void SetTransactionIdForTesting(absl::string_view transaction_id);
+
+ // Contruct a copy of `this`.
+ std::unique_ptr<StunMessage> Clone() const;
+
+ // Check if the attributes of this StunMessage equals those of `other`
+ // for all attributes that `attribute_type_mask` return true
+ bool EqualAttributes(const StunMessage* other,
+ std::function<bool(int type)> attribute_type_mask) const;
+
+ // Validates that a STUN message in byte buffer form
+ // has a correct MESSAGE-INTEGRITY value.
+ // These functions are not recommended and will be deprecated; use
+ // ValidateMessageIntegrity(password) on the parsed form instead.
+ [[deprecated("Use member function")]] static bool ValidateMessageIntegrity(
+ const char* data,
+ size_t size,
+ const std::string& password);
+ [[deprecated("Use member function")]] static bool ValidateMessageIntegrity32(
+ const char* data,
+ size_t size,
+ const std::string& password);
+
+ // Expose raw-buffer ValidateMessageIntegrity function for testing.
+ static bool ValidateMessageIntegrityForTesting(const char* data,
+ size_t size,
+ const std::string& password);
+ // Expose raw-buffer ValidateMessageIntegrity function for testing.
+ static bool ValidateMessageIntegrity32ForTesting(const char* data,
+ size_t size,
+ const std::string& password);
+
+ protected:
+ // Verifies that the given attribute is allowed for this message.
+ virtual StunAttributeValueType GetAttributeValueType(int type) const;
+
+ std::vector<std::unique_ptr<StunAttribute>> attrs_;
+
+ private:
+ StunAttribute* CreateAttribute(int type, size_t length) /* const*/;
+ const StunAttribute* GetAttribute(int type) const;
+ static bool IsValidTransactionId(absl::string_view transaction_id);
+ bool AddMessageIntegrityOfType(int mi_attr_type,
+ size_t mi_attr_size,
+ absl::string_view key);
+ static bool ValidateMessageIntegrityOfType(int mi_attr_type,
+ size_t mi_attr_size,
+ const char* data,
+ size_t size,
+ const std::string& password);
+
+ uint16_t type_ = STUN_INVALID_MESSAGE_TYPE;
+ uint16_t length_ = 0;
+ std::string transaction_id_;
+ uint32_t reduced_transaction_id_ = 0;
+ uint32_t stun_magic_cookie_ = kStunMagicCookie;
+ // The original buffer for messages created by Read().
+ std::string buffer_;
+ IntegrityStatus integrity_ = IntegrityStatus::kNotSet;
+ std::string password_;
+};
+
+// Base class for all STUN/TURN attributes.
+class StunAttribute {
+ public:
+ virtual ~StunAttribute() {}
+
+ int type() const { return type_; }
+ size_t length() const { return length_; }
+
+ // Return the type of this attribute.
+ virtual StunAttributeValueType value_type() const = 0;
+
+ // Only XorAddressAttribute needs this so far.
+ virtual void SetOwner(StunMessage* owner) {}
+
+ // Reads the body (not the type or length) for this type of attribute from
+ // the given buffer. Return value is true if successful.
+ virtual bool Read(rtc::ByteBufferReader* buf) = 0;
+
+ // Writes the body (not the type or length) to the given buffer. Return
+ // value is true if successful.
+ virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
+
+ // Creates an attribute object with the given type and smallest length.
+ static StunAttribute* Create(StunAttributeValueType value_type,
+ uint16_t type,
+ uint16_t length,
+ StunMessage* owner);
+ // TODO(?): Allow these create functions to take parameters, to reduce
+ // the amount of work callers need to do to initialize attributes.
+ static std::unique_ptr<StunAddressAttribute> CreateAddress(uint16_t type);
+ static std::unique_ptr<StunXorAddressAttribute> CreateXorAddress(
+ uint16_t type);
+ static std::unique_ptr<StunUInt32Attribute> CreateUInt32(uint16_t type);
+ static std::unique_ptr<StunUInt64Attribute> CreateUInt64(uint16_t type);
+ static std::unique_ptr<StunByteStringAttribute> CreateByteString(
+ uint16_t type);
+ static std::unique_ptr<StunUInt16ListAttribute> CreateUInt16ListAttribute(
+ uint16_t type);
+ static std::unique_ptr<StunErrorCodeAttribute> CreateErrorCode();
+ static std::unique_ptr<StunUInt16ListAttribute> CreateUnknownAttributes();
+
+ protected:
+ StunAttribute(uint16_t type, uint16_t length);
+ void SetLength(uint16_t length) { length_ = length; }
+ void WritePadding(rtc::ByteBufferWriter* buf) const;
+ void ConsumePadding(rtc::ByteBufferReader* buf) const;
+
+ private:
+ uint16_t type_;
+ uint16_t length_;
+};
+
+// Implements STUN attributes that record an Internet address.
+class StunAddressAttribute : public StunAttribute {
+ public:
+ static const uint16_t SIZE_UNDEF = 0;
+ static const uint16_t SIZE_IP4 = 8;
+ static const uint16_t SIZE_IP6 = 20;
+ StunAddressAttribute(uint16_t type, const rtc::SocketAddress& addr);
+ StunAddressAttribute(uint16_t type, uint16_t length);
+
+ StunAttributeValueType value_type() const override;
+
+ StunAddressFamily family() const {
+ switch (address_.ipaddr().family()) {
+ case AF_INET:
+ return STUN_ADDRESS_IPV4;
+ case AF_INET6:
+ return STUN_ADDRESS_IPV6;
+ }
+ return STUN_ADDRESS_UNDEF;
+ }
+
+ const rtc::SocketAddress& GetAddress() const { return address_; }
+ const rtc::IPAddress& ipaddr() const { return address_.ipaddr(); }
+ uint16_t port() const { return address_.port(); }
+
+ void SetAddress(const rtc::SocketAddress& addr) {
+ address_ = addr;
+ EnsureAddressLength();
+ }
+ void SetIP(const rtc::IPAddress& ip) {
+ address_.SetIP(ip);
+ EnsureAddressLength();
+ }
+ void SetPort(uint16_t port) { address_.SetPort(port); }
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ void EnsureAddressLength() {
+ switch (family()) {
+ case STUN_ADDRESS_IPV4: {
+ SetLength(SIZE_IP4);
+ break;
+ }
+ case STUN_ADDRESS_IPV6: {
+ SetLength(SIZE_IP6);
+ break;
+ }
+ default: {
+ SetLength(SIZE_UNDEF);
+ break;
+ }
+ }
+ }
+ rtc::SocketAddress address_;
+};
+
+// Implements STUN attributes that record an Internet address. When encoded
+// in a STUN message, the address contained in this attribute is XORed with the
+// transaction ID of the message.
+class StunXorAddressAttribute : public StunAddressAttribute {
+ public:
+ StunXorAddressAttribute(uint16_t type, const rtc::SocketAddress& addr);
+ StunXorAddressAttribute(uint16_t type, uint16_t length, StunMessage* owner);
+
+ StunAttributeValueType value_type() const override;
+ void SetOwner(StunMessage* owner) override;
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ rtc::IPAddress GetXoredIP() const;
+ StunMessage* owner_;
+};
+
+// Implements STUN attributes that record a 32-bit integer.
+class StunUInt32Attribute : public StunAttribute {
+ public:
+ static const uint16_t SIZE = 4;
+ StunUInt32Attribute(uint16_t type, uint32_t value);
+ explicit StunUInt32Attribute(uint16_t type);
+
+ StunAttributeValueType value_type() const override;
+
+ uint32_t value() const { return bits_; }
+ void SetValue(uint32_t bits) { bits_ = bits; }
+
+ bool GetBit(size_t index) const;
+ void SetBit(size_t index, bool value);
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ uint32_t bits_;
+};
+
+class StunUInt64Attribute : public StunAttribute {
+ public:
+ static const uint16_t SIZE = 8;
+ StunUInt64Attribute(uint16_t type, uint64_t value);
+ explicit StunUInt64Attribute(uint16_t type);
+
+ StunAttributeValueType value_type() const override;
+
+ uint64_t value() const { return bits_; }
+ void SetValue(uint64_t bits) { bits_ = bits; }
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ uint64_t bits_;
+};
+
+// Implements STUN attributes that record an arbitrary byte string.
+class StunByteStringAttribute : public StunAttribute {
+ public:
+ explicit StunByteStringAttribute(uint16_t type);
+ StunByteStringAttribute(uint16_t type, absl::string_view str);
+ StunByteStringAttribute(uint16_t type, const void* bytes, size_t length);
+ StunByteStringAttribute(uint16_t type, uint16_t length);
+ ~StunByteStringAttribute() override;
+
+ StunAttributeValueType value_type() const override;
+
+ const char* bytes() const { return bytes_; }
+ absl::string_view string_view() const {
+ return absl::string_view(bytes_, length());
+ }
+
+ [[deprecated]] std::string GetString() const {
+ return std::string(bytes_, length());
+ }
+
+ void CopyBytes(const void* bytes, size_t length);
+ void CopyBytes(absl::string_view bytes);
+
+ uint8_t GetByte(size_t index) const;
+ void SetByte(size_t index, uint8_t value);
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ void SetBytes(char* bytes, size_t length);
+
+ char* bytes_;
+};
+
+// Implements STUN attributes that record an error code.
+class StunErrorCodeAttribute : public StunAttribute {
+ public:
+ static const uint16_t MIN_SIZE;
+ StunErrorCodeAttribute(uint16_t type, int code, const std::string& reason);
+ StunErrorCodeAttribute(uint16_t type, uint16_t length);
+ ~StunErrorCodeAttribute() override;
+
+ StunAttributeValueType value_type() const override;
+
+ // The combined error and class, e.g. 0x400.
+ int code() const;
+ void SetCode(int code);
+
+ // The individual error components.
+ int eclass() const { return class_; }
+ int number() const { return number_; }
+ const std::string& reason() const { return reason_; }
+ void SetClass(uint8_t eclass) { class_ = eclass; }
+ void SetNumber(uint8_t number) { number_ = number; }
+ void SetReason(const std::string& reason);
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ uint8_t class_;
+ uint8_t number_;
+ std::string reason_;
+};
+
+// Implements STUN attributes that record a list of attribute names.
+class StunUInt16ListAttribute : public StunAttribute {
+ public:
+ StunUInt16ListAttribute(uint16_t type, uint16_t length);
+ ~StunUInt16ListAttribute() override;
+
+ StunAttributeValueType value_type() const override;
+
+ size_t Size() const;
+ uint16_t GetType(int index) const;
+ void SetType(int index, uint16_t value);
+ void AddType(uint16_t value);
+ void AddTypeAtIndex(uint16_t index, uint16_t value);
+
+ bool Read(rtc::ByteBufferReader* buf) override;
+ bool Write(rtc::ByteBufferWriter* buf) const override;
+
+ private:
+ std::vector<uint16_t>* attr_types_;
+};
+
+// Return a string e.g "STUN BINDING request".
+std::string StunMethodToString(int msg_type);
+
+// Returns the (successful) response type for the given request type.
+// Returns -1 if `request_type` is not a valid request type.
+int GetStunSuccessResponseType(int request_type);
+
+// Returns the error response type for the given request type.
+// Returns -1 if `request_type` is not a valid request type.
+int GetStunErrorResponseType(int request_type);
+
+// Returns whether a given message is a request type.
+bool IsStunRequestType(int msg_type);
+
+// Returns whether a given message is an indication type.
+bool IsStunIndicationType(int msg_type);
+
+// Returns whether a given response is a success type.
+bool IsStunSuccessResponseType(int msg_type);
+
+// Returns whether a given response is an error type.
+bool IsStunErrorResponseType(int msg_type);
+
+// Computes the STUN long-term credential hash.
+bool ComputeStunCredentialHash(const std::string& username,
+ const std::string& realm,
+ const std::string& password,
+ std::string* hash);
+
+// Make a copy af `attribute` and return a new StunAttribute.
+// This is useful if you don't care about what kind of attribute you
+// are handling.
+//
+// The implementation copies by calling Write() followed by Read().
+//
+// If `tmp_buffer` is supplied this buffer will be used, otherwise
+// a buffer will created in the method.
+std::unique_ptr<StunAttribute> CopyStunAttribute(
+ const StunAttribute& attribute,
+ rtc::ByteBufferWriter* tmp_buffer_ptr = 0);
+
+// TODO(?): Move the TURN/ICE stuff below out to separate files.
+extern const char TURN_MAGIC_COOKIE_VALUE[4];
+
+// "GTURN" STUN methods.
+// TODO(?): Rename these methods to GTURN_ to make it clear they aren't
+// part of standard STUN/TURN.
+enum RelayMessageType {
+ // For now, using the same defs from TurnMessageType below.
+ // STUN_ALLOCATE_REQUEST = 0x0003,
+ // STUN_ALLOCATE_RESPONSE = 0x0103,
+ // STUN_ALLOCATE_ERROR_RESPONSE = 0x0113,
+ STUN_SEND_REQUEST = 0x0004,
+ STUN_SEND_RESPONSE = 0x0104,
+ STUN_SEND_ERROR_RESPONSE = 0x0114,
+ STUN_DATA_INDICATION = 0x0115,
+};
+
+// "GTURN"-specific STUN attributes.
+// TODO(?): Rename these attributes to GTURN_ to avoid conflicts.
+enum RelayAttributeType {
+ STUN_ATTR_LIFETIME = 0x000d, // UInt32
+ STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes
+ STUN_ATTR_BANDWIDTH = 0x0010, // UInt32
+ STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address
+ STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address
+ STUN_ATTR_DATA = 0x0013, // ByteString
+ STUN_ATTR_OPTIONS = 0x8001, // UInt32
+};
+
+// A "GTURN" STUN message.
+class RelayMessage : public StunMessage {
+ public:
+ using StunMessage::StunMessage;
+
+ protected:
+ StunAttributeValueType GetAttributeValueType(int type) const override;
+ StunMessage* CreateNew() const override;
+};
+
+// Defined in TURN RFC 5766.
+enum TurnMessageType : uint16_t {
+ STUN_ALLOCATE_REQUEST = 0x0003,
+ STUN_ALLOCATE_RESPONSE = 0x0103,
+ STUN_ALLOCATE_ERROR_RESPONSE = 0x0113,
+ TURN_REFRESH_REQUEST = 0x0004,
+ TURN_REFRESH_RESPONSE = 0x0104,
+ TURN_REFRESH_ERROR_RESPONSE = 0x0114,
+ TURN_SEND_INDICATION = 0x0016,
+ TURN_DATA_INDICATION = 0x0017,
+ TURN_CREATE_PERMISSION_REQUEST = 0x0008,
+ TURN_CREATE_PERMISSION_RESPONSE = 0x0108,
+ TURN_CREATE_PERMISSION_ERROR_RESPONSE = 0x0118,
+ TURN_CHANNEL_BIND_REQUEST = 0x0009,
+ TURN_CHANNEL_BIND_RESPONSE = 0x0109,
+ TURN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119,
+};
+
+enum TurnAttributeType {
+ STUN_ATTR_CHANNEL_NUMBER = 0x000C, // UInt32
+ STUN_ATTR_TURN_LIFETIME = 0x000d, // UInt32
+ STUN_ATTR_XOR_PEER_ADDRESS = 0x0012, // XorAddress
+ // TODO(mallinath) - Uncomment after RelayAttributes are renamed.
+ // STUN_ATTR_DATA = 0x0013, // ByteString
+ STUN_ATTR_XOR_RELAYED_ADDRESS = 0x0016, // XorAddress
+ STUN_ATTR_EVEN_PORT = 0x0018, // ByteString, 1 byte.
+ STUN_ATTR_REQUESTED_TRANSPORT = 0x0019, // UInt32
+ STUN_ATTR_DONT_FRAGMENT = 0x001A, // No content, Length = 0
+ STUN_ATTR_RESERVATION_TOKEN = 0x0022, // ByteString, 8 bytes.
+ // TODO(mallinath) - Rename STUN_ATTR_TURN_LIFETIME to STUN_ATTR_LIFETIME and
+ // STUN_ATTR_TURN_DATA to STUN_ATTR_DATA. Also rename RelayMessage attributes
+ // by appending G to attribute name.
+};
+
+// RFC 5766-defined errors.
+enum TurnErrorType {
+ STUN_ERROR_FORBIDDEN = 403,
+ STUN_ERROR_ALLOCATION_MISMATCH = 437,
+ STUN_ERROR_WRONG_CREDENTIALS = 441,
+ STUN_ERROR_UNSUPPORTED_PROTOCOL = 442
+};
+
+extern const int SERVER_NOT_REACHABLE_ERROR;
+
+extern const char STUN_ERROR_REASON_FORBIDDEN[];
+extern const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[];
+extern const char STUN_ERROR_REASON_WRONG_CREDENTIALS[];
+extern const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[];
+class TurnMessage : public StunMessage {
+ public:
+ using StunMessage::StunMessage;
+
+ protected:
+ StunAttributeValueType GetAttributeValueType(int type) const override;
+ StunMessage* CreateNew() const override;
+};
+
+enum IceAttributeType {
+ // RFC 5245 ICE STUN attributes.
+ STUN_ATTR_PRIORITY = 0x0024, // UInt32
+ STUN_ATTR_USE_CANDIDATE = 0x0025, // No content, Length = 0
+ STUN_ATTR_ICE_CONTROLLED = 0x8029, // UInt64
+ STUN_ATTR_ICE_CONTROLLING = 0x802A, // UInt64
+ // The following attributes are in the comprehension-optional range
+ // (0xC000-0xFFFF) and are not registered with IANA. These STUN attributes are
+ // intended for ICE and should NOT be used in generic use cases of STUN
+ // messages.
+ //
+ // Note that the value 0xC001 has already been assigned by IANA to
+ // ENF-FLOW-DESCRIPTION
+ // (https://www.iana.org/assignments/stun-parameters/stun-parameters.xml).
+ STUN_ATTR_NOMINATION = 0xC001, // UInt32
+ // UInt32. The higher 16 bits are the network ID. The lower 16 bits are the
+ // network cost.
+ STUN_ATTR_GOOG_NETWORK_INFO = 0xC057,
+ // Experimental: Transaction ID of the last connectivity check received.
+ STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED = 0xC058,
+ // Uint16List. Miscellaneous attributes for future extension.
+ STUN_ATTR_GOOG_MISC_INFO = 0xC059,
+ // Obsolete.
+ STUN_ATTR_GOOG_OBSOLETE_1 = 0xC05A,
+ STUN_ATTR_GOOG_CONNECTION_ID = 0xC05B, // Not yet implemented.
+ STUN_ATTR_GOOG_DELTA = 0xC05C, // Not yet implemented.
+ STUN_ATTR_GOOG_DELTA_ACK = 0xC05D, // Not yet implemented.
+ // MESSAGE-INTEGRITY truncated to 32-bit.
+ STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32 = 0xC060,
+};
+
+// When adding new attributes to STUN_ATTR_GOOG_MISC_INFO
+// (which is a list of uint16_t), append the indices of these attributes below
+// and do NOT change the existing indices. The indices of attributes must be
+// consistent with those used in ConnectionRequest::Prepare when forming a STUN
+// message for the ICE connectivity check, and they are used when parsing a
+// received STUN message.
+enum class IceGoogMiscInfoBindingRequestAttributeIndex {
+ SUPPORT_GOOG_PING_VERSION = 0,
+};
+
+enum class IceGoogMiscInfoBindingResponseAttributeIndex {
+ SUPPORT_GOOG_PING_VERSION = 0,
+};
+
+// RFC 5245-defined errors.
+enum IceErrorCode {
+ STUN_ERROR_ROLE_CONFLICT = 487,
+};
+extern const char STUN_ERROR_REASON_ROLE_CONFLICT[];
+
+// A RFC 5245 ICE STUN message.
+class IceMessage : public StunMessage {
+ public:
+ using StunMessage::StunMessage;
+
+ protected:
+ StunAttributeValueType GetAttributeValueType(int type) const override;
+ StunMessage* CreateNew() const override;
+};
+
+} // namespace cricket
+
+#endif // API_TRANSPORT_STUN_H_
diff --git a/third_party/libwebrtc/api/transport/stun_types_gn/moz.build b/third_party/libwebrtc/api/transport/stun_types_gn/moz.build
new file mode 100644
index 0000000000..dd75da361b
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/stun_types_gn/moz.build
@@ -0,0 +1,201 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("stun_types_gn")
diff --git a/third_party/libwebrtc/api/transport/stun_unittest.cc b/third_party/libwebrtc/api/transport/stun_unittest.cc
new file mode 100644
index 0000000000..96ad45843b
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/stun_unittest.cc
@@ -0,0 +1,1882 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/transport/stun.h"
+
+#include <string.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/byte_buffer.h"
+#include "rtc_base/byte_order.h"
+#include "rtc_base/socket_address.h"
+#include "system_wrappers/include/metrics.h"
+#include "test/gtest.h"
+
+namespace cricket {
+
+class StunTest : public ::testing::Test {
+ protected:
+ void CheckStunHeader(const StunMessage& msg,
+ StunMessageType expected_type,
+ size_t expected_length) {
+ ASSERT_EQ(expected_type, msg.type());
+ ASSERT_EQ(expected_length, msg.length());
+ }
+
+ void CheckStunTransactionID(const StunMessage& msg,
+ const unsigned char* expectedID,
+ size_t length) {
+ ASSERT_EQ(length, msg.transaction_id().size());
+ ASSERT_EQ(length == kStunTransactionIdLength + 4, msg.IsLegacy());
+ ASSERT_EQ(length == kStunTransactionIdLength, !msg.IsLegacy());
+ ASSERT_EQ(0, memcmp(msg.transaction_id().c_str(), expectedID, length));
+ }
+
+ void CheckStunAddressAttribute(const StunAddressAttribute* addr,
+ StunAddressFamily expected_family,
+ int expected_port,
+ const rtc::IPAddress& expected_address) {
+ ASSERT_EQ(expected_family, addr->family());
+ ASSERT_EQ(expected_port, addr->port());
+
+ if (addr->family() == STUN_ADDRESS_IPV4) {
+ in_addr v4_address = expected_address.ipv4_address();
+ in_addr stun_address = addr->ipaddr().ipv4_address();
+ ASSERT_EQ(0, memcmp(&v4_address, &stun_address, sizeof(stun_address)));
+ } else if (addr->family() == STUN_ADDRESS_IPV6) {
+ in6_addr v6_address = expected_address.ipv6_address();
+ in6_addr stun_address = addr->ipaddr().ipv6_address();
+ ASSERT_EQ(0, memcmp(&v6_address, &stun_address, sizeof(stun_address)));
+ } else {
+ ASSERT_TRUE(addr->family() == STUN_ADDRESS_IPV6 ||
+ addr->family() == STUN_ADDRESS_IPV4);
+ }
+ }
+
+ size_t ReadStunMessageTestCase(StunMessage* msg,
+ const unsigned char* testcase,
+ size_t size) {
+ const char* input = reinterpret_cast<const char*>(testcase);
+ rtc::ByteBufferReader buf(input, size);
+ if (msg->Read(&buf)) {
+ // Returns the size the stun message should report itself as being
+ return (size - 20);
+ } else {
+ return 0;
+ }
+ }
+};
+
+// Sample STUN packets with various attributes
+// Gathered by wiresharking pjproject's pjnath test programs
+// pjproject available at www.pjsip.org
+
+// clang-format off
+// clang formatting doesn't respect inline comments.
+
+static const unsigned char kStunMessageWithIPv6MappedAddress[] = {
+ 0x00, 0x01, 0x00, 0x18, // message header
+ 0x21, 0x12, 0xa4, 0x42, // transaction id
+ 0x29, 0x1f, 0xcd, 0x7c,
+ 0xba, 0x58, 0xab, 0xd7,
+ 0xf2, 0x41, 0x01, 0x00,
+ 0x00, 0x01, 0x00, 0x14, // Address type (mapped), length
+ 0x00, 0x02, 0xb8, 0x81, // family (IPv6), port
+ 0x24, 0x01, 0xfa, 0x00, // an IPv6 address
+ 0x00, 0x04, 0x10, 0x00,
+ 0xbe, 0x30, 0x5b, 0xff,
+ 0xfe, 0xe5, 0x00, 0xc3
+};
+
+static const unsigned char kStunMessageWithIPv4MappedAddress[] = {
+ 0x01, 0x01, 0x00, 0x0c, // binding response, length 12
+ 0x21, 0x12, 0xa4, 0x42, // magic cookie
+ 0x29, 0x1f, 0xcd, 0x7c, // transaction ID
+ 0xba, 0x58, 0xab, 0xd7,
+ 0xf2, 0x41, 0x01, 0x00,
+ 0x00, 0x01, 0x00, 0x08, // Mapped, 8 byte length
+ 0x00, 0x01, 0x9d, 0xfc, // AF_INET, unxor-ed port
+ 0xac, 0x17, 0x44, 0xe6 // IPv4 address
+};
+
+// Test XOR-mapped IP addresses:
+static const unsigned char kStunMessageWithIPv6XorMappedAddress[] = {
+ 0x01, 0x01, 0x00, 0x18, // message header (binding response)
+ 0x21, 0x12, 0xa4, 0x42, // magic cookie (rfc5389)
+ 0xe3, 0xa9, 0x46, 0xe1, // transaction ID
+ 0x7c, 0x00, 0xc2, 0x62,
+ 0x54, 0x08, 0x01, 0x00,
+ 0x00, 0x20, 0x00, 0x14, // Address Type (XOR), length
+ 0x00, 0x02, 0xcb, 0x5b, // family, XOR-ed port
+ 0x05, 0x13, 0x5e, 0x42, // XOR-ed IPv6 address
+ 0xe3, 0xad, 0x56, 0xe1,
+ 0xc2, 0x30, 0x99, 0x9d,
+ 0xaa, 0xed, 0x01, 0xc3
+};
+
+static const unsigned char kStunMessageWithIPv4XorMappedAddress[] = {
+ 0x01, 0x01, 0x00, 0x0c, // message header (binding response)
+ 0x21, 0x12, 0xa4, 0x42, // magic cookie
+ 0x29, 0x1f, 0xcd, 0x7c, // transaction ID
+ 0xba, 0x58, 0xab, 0xd7,
+ 0xf2, 0x41, 0x01, 0x00,
+ 0x00, 0x20, 0x00, 0x08, // address type (xor), length
+ 0x00, 0x01, 0xfc, 0xb5, // family (AF_INET), XOR-ed port
+ 0x8d, 0x05, 0xe0, 0xa4 // IPv4 address
+};
+
+// ByteString Attribute (username)
+static const unsigned char kStunMessageWithByteStringAttribute[] = {
+ 0x00, 0x01, 0x00, 0x0c,
+ 0x21, 0x12, 0xa4, 0x42,
+ 0xe3, 0xa9, 0x46, 0xe1,
+ 0x7c, 0x00, 0xc2, 0x62,
+ 0x54, 0x08, 0x01, 0x00,
+ 0x00, 0x06, 0x00, 0x08, // username attribute (length 8)
+ 0x61, 0x62, 0x63, 0x64, // abcdefgh
+ 0x65, 0x66, 0x67, 0x68
+};
+
+// Message with an unknown but comprehensible optional attribute.
+// Parsing should succeed despite this unknown attribute.
+static const unsigned char kStunMessageWithUnknownAttribute[] = {
+ 0x00, 0x01, 0x00, 0x14,
+ 0x21, 0x12, 0xa4, 0x42,
+ 0xe3, 0xa9, 0x46, 0xe1,
+ 0x7c, 0x00, 0xc2, 0x62,
+ 0x54, 0x08, 0x01, 0x00,
+ 0x00, 0xaa, 0x00, 0x07, // Unknown attribute, length 7 (needs padding!)
+ 0x61, 0x62, 0x63, 0x64, // abcdefg + padding
+ 0x65, 0x66, 0x67, 0x00,
+ 0x00, 0x06, 0x00, 0x03, // Followed by a known attribute we can
+ 0x61, 0x62, 0x63, 0x00 // check for (username of length 3)
+};
+
+// ByteString Attribute (username) with padding byte
+static const unsigned char kStunMessageWithPaddedByteStringAttribute[] = {
+ 0x00, 0x01, 0x00, 0x08,
+ 0x21, 0x12, 0xa4, 0x42,
+ 0xe3, 0xa9, 0x46, 0xe1,
+ 0x7c, 0x00, 0xc2, 0x62,
+ 0x54, 0x08, 0x01, 0x00,
+ 0x00, 0x06, 0x00, 0x03, // username attribute (length 3)
+ 0x61, 0x62, 0x63, 0xcc // abc
+};
+
+// Message with an Unknown Attributes (uint16_t list) attribute.
+static const unsigned char kStunMessageWithUInt16ListAttribute[] = {
+ 0x00, 0x01, 0x00, 0x0c,
+ 0x21, 0x12, 0xa4, 0x42,
+ 0xe3, 0xa9, 0x46, 0xe1,
+ 0x7c, 0x00, 0xc2, 0x62,
+ 0x54, 0x08, 0x01, 0x00,
+ 0x00, 0x0a, 0x00, 0x06, // username attribute (length 6)
+ 0x00, 0x01, 0x10, 0x00, // three attributes plus padding
+ 0xAB, 0xCU, 0xBE, 0xEF
+};
+
+// Error response message (unauthorized)
+static const unsigned char kStunMessageWithErrorAttribute[] = {
+ 0x01, 0x11, 0x00, 0x14,
+ 0x21, 0x12, 0xa4, 0x42,
+ 0x29, 0x1f, 0xcd, 0x7c,
+ 0xba, 0x58, 0xab, 0xd7,
+ 0xf2, 0x41, 0x01, 0x00,
+ 0x00, 0x09, 0x00, 0x10,
+ 0x00, 0x00, 0x04, 0x01,
+ 0x55, 0x6e, 0x61, 0x75,
+ 0x74, 0x68, 0x6f, 0x72,
+ 0x69, 0x7a, 0x65, 0x64
+};
+
+// Sample messages with an invalid length Field
+
+// The actual length in bytes of the invalid messages (including STUN header)
+static const int kRealLengthOfInvalidLengthTestCases = 32;
+
+static const unsigned char kStunMessageWithZeroLength[] = {
+ 0x00, 0x01, 0x00, 0x00, // length of 0 (last 2 bytes)
+ 0x21, 0x12, 0xA4, 0x42, // magic cookie
+ '0', '1', '2', '3', // transaction id
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 0x00, 0x20, 0x00, 0x08, // xor mapped address
+ 0x00, 0x01, 0x21, 0x1F,
+ 0x21, 0x12, 0xA4, 0x53,
+};
+
+static const unsigned char kStunMessageWithExcessLength[] = {
+ 0x00, 0x01, 0x00, 0x55, // length of 85
+ 0x21, 0x12, 0xA4, 0x42, // magic cookie
+ '0', '1', '2', '3', // transaction id
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 0x00, 0x20, 0x00, 0x08, // xor mapped address
+ 0x00, 0x01, 0x21, 0x1F,
+ 0x21, 0x12, 0xA4, 0x53,
+};
+
+static const unsigned char kStunMessageWithSmallLength[] = {
+ 0x00, 0x01, 0x00, 0x03, // length of 3
+ 0x21, 0x12, 0xA4, 0x42, // magic cookie
+ '0', '1', '2', '3', // transaction id
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 0x00, 0x20, 0x00, 0x08, // xor mapped address
+ 0x00, 0x01, 0x21, 0x1F,
+ 0x21, 0x12, 0xA4, 0x53,
+};
+
+static const unsigned char kStunMessageWithBadHmacAtEnd[] = {
+ 0x00, 0x01, 0x00, 0x14, // message length exactly 20
+ 0x21, 0x12, 0xA4, 0x42, // magic cookie
+ '0', '1', '2', '3', // transaction ID
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 0x00, 0x08, 0x00, 0x14, // type=STUN_ATTR_MESSAGE_INTEGRITY, length=20
+ '0', '0', '0', '0', // We lied, there are only 16 bytes of HMAC.
+ '0', '0', '0', '0',
+ '0', '0', '0', '0',
+ '0', '0', '0', '0',
+};
+
+// RTCP packet, for testing we correctly ignore non stun packet types.
+// V=2, P=false, RC=0, Type=200, Len=6, Sender-SSRC=85, etc
+static const unsigned char kRtcpPacket[] = {
+ 0x80, 0xc8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55,
+ 0xce, 0xa5, 0x18, 0x3a, 0x39, 0xcc, 0x7d, 0x09,
+ 0x23, 0xed, 0x19, 0x07, 0x00, 0x00, 0x01, 0x56,
+ 0x00, 0x03, 0x73, 0x50,
+};
+
+
+// RFC5769 Test Vectors
+// Software name (request): "STUN test client" (without quotes)
+// Software name (response): "test vector" (without quotes)
+// Username: "evtj:h6vY" (without quotes)
+// Password: "VOkJxbRl1RmTxUk/WvJxBt" (without quotes)
+static const unsigned char kRfc5769SampleMsgTransactionId[] = {
+ 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae
+};
+static const char kRfc5769SampleMsgClientSoftware[] = "STUN test client";
+static const char kRfc5769SampleMsgServerSoftware[] = "test vector";
+static const char kRfc5769SampleMsgUsername[] = "evtj:h6vY";
+static const char kRfc5769SampleMsgPassword[] = "VOkJxbRl1RmTxUk/WvJxBt";
+static const rtc::SocketAddress kRfc5769SampleMsgMappedAddress(
+ "192.0.2.1", 32853);
+static const rtc::SocketAddress kRfc5769SampleMsgIPv6MappedAddress(
+ "2001:db8:1234:5678:11:2233:4455:6677", 32853);
+
+static const unsigned char kRfc5769SampleMsgWithAuthTransactionId[] = {
+ 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e
+};
+static const char kRfc5769SampleMsgWithAuthUsername[] =
+ "\xe3\x83\x9e\xe3\x83\x88\xe3\x83\xaa\xe3\x83\x83\xe3\x82\xaf\xe3\x82\xb9";
+static const char kRfc5769SampleMsgWithAuthPassword[] = "TheMatrIX";
+static const char kRfc5769SampleMsgWithAuthNonce[] =
+ "f//499k954d6OL34oL9FSTvy64sA";
+static const char kRfc5769SampleMsgWithAuthRealm[] = "example.org";
+
+// 2.1. Sample Request
+static const unsigned char kRfc5769SampleRequest[] = {
+ 0x00, 0x01, 0x00, 0x58, // Request type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header
+ 0x53, 0x54, 0x55, 0x4e, // }
+ 0x20, 0x74, 0x65, 0x73, // } User-agent...
+ 0x74, 0x20, 0x63, 0x6c, // } ...name
+ 0x69, 0x65, 0x6e, 0x74, // }
+ 0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header
+ 0x6e, 0x00, 0x01, 0xff, // ICE priority value
+ 0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header
+ 0x93, 0x2f, 0xf9, 0xb1, // } Pseudo-random tie breaker...
+ 0x51, 0x26, 0x3b, 0x36, // } ...for ICE control
+ 0x00, 0x06, 0x00, 0x09, // USERNAME attribute header
+ 0x65, 0x76, 0x74, 0x6a, // }
+ 0x3a, 0x68, 0x36, 0x76, // } Username (9 bytes) and padding (3 bytes)
+ 0x59, 0x20, 0x20, 0x20, // }
+ 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header
+ 0x9a, 0xea, 0xa7, 0x0c, // }
+ 0xbf, 0xd8, 0xcb, 0x56, // }
+ 0x78, 0x1e, 0xf2, 0xb5, // } HMAC-SHA1 fingerprint
+ 0xb2, 0xd3, 0xf2, 0x49, // }
+ 0xc1, 0xb5, 0x71, 0xa2, // }
+ 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header
+ 0xe5, 0x7a, 0x3b, 0xcf // CRC32 fingerprint
+};
+
+// 2.1. Sample Request
+static const unsigned char kSampleRequestMI32[] = {
+ 0x00, 0x01, 0x00, 0x48, // Request type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header
+ 0x53, 0x54, 0x55, 0x4e, // }
+ 0x20, 0x74, 0x65, 0x73, // } User-agent...
+ 0x74, 0x20, 0x63, 0x6c, // } ...name
+ 0x69, 0x65, 0x6e, 0x74, // }
+ 0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header
+ 0x6e, 0x00, 0x01, 0xff, // ICE priority value
+ 0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header
+ 0x93, 0x2f, 0xf9, 0xb1, // } Pseudo-random tie breaker...
+ 0x51, 0x26, 0x3b, 0x36, // } ...for ICE control
+ 0x00, 0x06, 0x00, 0x09, // USERNAME attribute header
+ 0x65, 0x76, 0x74, 0x6a, // }
+ 0x3a, 0x68, 0x36, 0x76, // } Username (9 bytes) and padding (3 bytes)
+ 0x59, 0x20, 0x20, 0x20, // }
+ 0xC0, 0x60, 0x00, 0x04, // MESSAGE-INTEGRITY-32 attribute header
+ 0x45, 0x45, 0xce, 0x7c, // } HMAC-SHA1 fingerprint (first 32 bit)
+ 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header
+ 0xe5, 0x7a, 0x3b, 0xcf // CRC32 fingerprint
+};
+
+// 2.2. Sample IPv4 Response
+static const unsigned char kRfc5769SampleResponse[] = {
+ 0x01, 0x01, 0x00, 0x3c, // Response type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header
+ 0x74, 0x65, 0x73, 0x74, // }
+ 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name
+ 0x74, 0x6f, 0x72, 0x20, // }
+ 0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header
+ 0x00, 0x01, 0xa1, 0x47, // Address family (IPv4) and xor'd mapped port
+ 0xe1, 0x12, 0xa6, 0x43, // Xor'd mapped IPv4 address
+ 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header
+ 0x2b, 0x91, 0xf5, 0x99, // }
+ 0xfd, 0x9e, 0x90, 0xc3, // }
+ 0x8c, 0x74, 0x89, 0xf9, // } HMAC-SHA1 fingerprint
+ 0x2a, 0xf9, 0xba, 0x53, // }
+ 0xf0, 0x6b, 0xe7, 0xd7, // }
+ 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header
+ 0xc0, 0x7d, 0x4c, 0x96 // CRC32 fingerprint
+};
+
+// 2.3. Sample IPv6 Response
+static const unsigned char kRfc5769SampleResponseIPv6[] = {
+ 0x01, 0x01, 0x00, 0x48, // Response type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header
+ 0x74, 0x65, 0x73, 0x74, // }
+ 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name
+ 0x74, 0x6f, 0x72, 0x20, // }
+ 0x00, 0x20, 0x00, 0x14, // XOR-MAPPED-ADDRESS attribute header
+ 0x00, 0x02, 0xa1, 0x47, // Address family (IPv6) and xor'd mapped port.
+ 0x01, 0x13, 0xa9, 0xfa, // }
+ 0xa5, 0xd3, 0xf1, 0x79, // } Xor'd mapped IPv6 address
+ 0xbc, 0x25, 0xf4, 0xb5, // }
+ 0xbe, 0xd2, 0xb9, 0xd9, // }
+ 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header
+ 0xa3, 0x82, 0x95, 0x4e, // }
+ 0x4b, 0xe6, 0x7b, 0xf1, // }
+ 0x17, 0x84, 0xc9, 0x7c, // } HMAC-SHA1 fingerprint
+ 0x82, 0x92, 0xc2, 0x75, // }
+ 0xbf, 0xe3, 0xed, 0x41, // }
+ 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header
+ 0xc8, 0xfb, 0x0b, 0x4c // CRC32 fingerprint
+};
+
+// 2.4. Sample Request with Long-Term Authentication
+static const unsigned char kRfc5769SampleRequestLongTermAuth[] = {
+ 0x00, 0x01, 0x00, 0x60, // Request type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0x78, 0xad, 0x34, 0x33, // }
+ 0xc6, 0xad, 0x72, 0xc0, // } Transaction ID
+ 0x29, 0xda, 0x41, 0x2e, // }
+ 0x00, 0x06, 0x00, 0x12, // USERNAME attribute header
+ 0xe3, 0x83, 0x9e, 0xe3, // }
+ 0x83, 0x88, 0xe3, 0x83, // }
+ 0xaa, 0xe3, 0x83, 0x83, // } Username value (18 bytes) and padding (2 bytes)
+ 0xe3, 0x82, 0xaf, 0xe3, // }
+ 0x82, 0xb9, 0x00, 0x00, // }
+ 0x00, 0x15, 0x00, 0x1c, // NONCE attribute header
+ 0x66, 0x2f, 0x2f, 0x34, // }
+ 0x39, 0x39, 0x6b, 0x39, // }
+ 0x35, 0x34, 0x64, 0x36, // }
+ 0x4f, 0x4c, 0x33, 0x34, // } Nonce value
+ 0x6f, 0x4c, 0x39, 0x46, // }
+ 0x53, 0x54, 0x76, 0x79, // }
+ 0x36, 0x34, 0x73, 0x41, // }
+ 0x00, 0x14, 0x00, 0x0b, // REALM attribute header
+ 0x65, 0x78, 0x61, 0x6d, // }
+ 0x70, 0x6c, 0x65, 0x2e, // } Realm value (11 bytes) and padding (1 byte)
+ 0x6f, 0x72, 0x67, 0x00, // }
+ 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header
+ 0xf6, 0x70, 0x24, 0x65, // }
+ 0x6d, 0xd6, 0x4a, 0x3e, // }
+ 0x02, 0xb8, 0xe0, 0x71, // } HMAC-SHA1 fingerprint
+ 0x2e, 0x85, 0xc9, 0xa2, // }
+ 0x8c, 0xa8, 0x96, 0x66 // }
+};
+
+// Length parameter is changed to 0x38 from 0x58.
+// AddMessageIntegrity will add MI information and update the length param
+// accordingly.
+static const unsigned char kRfc5769SampleRequestWithoutMI[] = {
+ 0x00, 0x01, 0x00, 0x38, // Request type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header
+ 0x53, 0x54, 0x55, 0x4e, // }
+ 0x20, 0x74, 0x65, 0x73, // } User-agent...
+ 0x74, 0x20, 0x63, 0x6c, // } ...name
+ 0x69, 0x65, 0x6e, 0x74, // }
+ 0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header
+ 0x6e, 0x00, 0x01, 0xff, // ICE priority value
+ 0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header
+ 0x93, 0x2f, 0xf9, 0xb1, // } Pseudo-random tie breaker...
+ 0x51, 0x26, 0x3b, 0x36, // } ...for ICE control
+ 0x00, 0x06, 0x00, 0x09, // USERNAME attribute header
+ 0x65, 0x76, 0x74, 0x6a, // }
+ 0x3a, 0x68, 0x36, 0x76, // } Username (9 bytes) and padding (3 bytes)
+ 0x59, 0x20, 0x20, 0x20 // }
+};
+
+// This HMAC differs from the RFC 5769 SampleRequest message. This differs
+// because spec uses 0x20 for the padding where as our implementation uses 0.
+static const unsigned char kCalculatedHmac1[] = {
+ 0x79, 0x07, 0xc2, 0xd2, // }
+ 0xed, 0xbf, 0xea, 0x48, // }
+ 0x0e, 0x4c, 0x76, 0xd8, // } HMAC-SHA1 fingerprint
+ 0x29, 0x62, 0xd5, 0xc3, // }
+ 0x74, 0x2a, 0xf9, 0xe3 // }
+};
+
+// This truncated HMAC differs from kCalculatedHmac1
+// above since the sum is computed including header
+// and the header is different since the message is shorter
+// than when MESSAGE-INTEGRITY is used.
+static const unsigned char kCalculatedHmac1_32[] = {
+ 0xda, 0x39, 0xde, 0x5d, // }
+};
+
+// Length parameter is changed to 0x1c from 0x3c.
+// AddMessageIntegrity will add MI information and update the length param
+// accordingly.
+static const unsigned char kRfc5769SampleResponseWithoutMI[] = {
+ 0x01, 0x01, 0x00, 0x1c, // Response type and message length
+ 0x21, 0x12, 0xa4, 0x42, // Magic cookie
+ 0xb7, 0xe7, 0xa7, 0x01, // }
+ 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
+ 0xfa, 0x87, 0xdf, 0xae, // }
+ 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header
+ 0x74, 0x65, 0x73, 0x74, // }
+ 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name
+ 0x74, 0x6f, 0x72, 0x20, // }
+ 0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header
+ 0x00, 0x01, 0xa1, 0x47, // Address family (IPv4) and xor'd mapped port
+ 0xe1, 0x12, 0xa6, 0x43 // Xor'd mapped IPv4 address
+};
+
+// This HMAC differs from the RFC 5769 SampleResponse message. This differs
+// because spec uses 0x20 for the padding where as our implementation uses 0.
+static const unsigned char kCalculatedHmac2[] = {
+ 0x5d, 0x6b, 0x58, 0xbe, // }
+ 0xad, 0x94, 0xe0, 0x7e, // }
+ 0xef, 0x0d, 0xfc, 0x12, // } HMAC-SHA1 fingerprint
+ 0x82, 0xa2, 0xbd, 0x08, // }
+ 0x43, 0x14, 0x10, 0x28 // }
+};
+
+// This truncated HMAC differs from kCalculatedHmac2
+// above since the sum is computed including header
+// and the header is different since the message is shorter
+// than when MESSAGE-INTEGRITY is used.
+static const unsigned char kCalculatedHmac2_32[] = {
+ 0xe7, 0x5c, 0xd3, 0x16, // }
+};
+
+// clang-format on
+
+// A transaction ID without the 'magic cookie' portion
+// pjnat's test programs use this transaction ID a lot.
+const unsigned char kTestTransactionId1[] = {0x029, 0x01f, 0x0cd, 0x07c,
+ 0x0ba, 0x058, 0x0ab, 0x0d7,
+ 0x0f2, 0x041, 0x001, 0x000};
+
+// They use this one sometimes too.
+const unsigned char kTestTransactionId2[] = {0x0e3, 0x0a9, 0x046, 0x0e1,
+ 0x07c, 0x000, 0x0c2, 0x062,
+ 0x054, 0x008, 0x001, 0x000};
+
+const in6_addr kIPv6TestAddress1 = {
+ {{0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+ 0xfe, 0xe5, 0x00, 0xc3}}};
+const in6_addr kIPv6TestAddress2 = {
+ {{0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x12, 0x06, 0x0c, 0xce, 0xff,
+ 0xfe, 0x1f, 0x61, 0xa4}}};
+
+#ifdef WEBRTC_POSIX
+const in_addr kIPv4TestAddress1 = {0xe64417ac};
+#elif defined WEBRTC_WIN
+// Windows in_addr has a union with a uchar[] array first.
+const in_addr kIPv4TestAddress1 = {{{0x0ac, 0x017, 0x044, 0x0e6}}};
+#endif
+const char kTestUserName1[] = "abcdefgh";
+const char kTestUserName2[] = "abc";
+const char kTestErrorReason[] = "Unauthorized";
+const int kTestErrorClass = 4;
+const int kTestErrorNumber = 1;
+const int kTestErrorCode = 401;
+
+const int kTestMessagePort1 = 59977;
+const int kTestMessagePort2 = 47233;
+const int kTestMessagePort3 = 56743;
+const int kTestMessagePort4 = 40444;
+
+#define ReadStunMessage(X, Y) ReadStunMessageTestCase(X, Y, sizeof(Y));
+
+// Test that the GetStun*Type and IsStun*Type methods work as expected.
+TEST_F(StunTest, MessageTypes) {
+ EXPECT_EQ(STUN_BINDING_RESPONSE,
+ GetStunSuccessResponseType(STUN_BINDING_REQUEST));
+ EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE,
+ GetStunErrorResponseType(STUN_BINDING_REQUEST));
+ EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_INDICATION));
+ EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_RESPONSE));
+ EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_ERROR_RESPONSE));
+ EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_INDICATION));
+ EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_RESPONSE));
+ EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_ERROR_RESPONSE));
+
+ int types[] = {STUN_BINDING_REQUEST, STUN_BINDING_INDICATION,
+ STUN_BINDING_RESPONSE, STUN_BINDING_ERROR_RESPONSE};
+ for (size_t i = 0; i < arraysize(types); ++i) {
+ EXPECT_EQ(i == 0U, IsStunRequestType(types[i]));
+ EXPECT_EQ(i == 1U, IsStunIndicationType(types[i]));
+ EXPECT_EQ(i == 2U, IsStunSuccessResponseType(types[i]));
+ EXPECT_EQ(i == 3U, IsStunErrorResponseType(types[i]));
+ EXPECT_EQ(1, types[i] & 0xFEEF);
+ }
+}
+
+TEST_F(StunTest, ReadMessageWithIPv4AddressAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4MappedAddress);
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::IPAddress test_address(kIPv4TestAddress1);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, kTestMessagePort4,
+ test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv4XorAddressAttribute) {
+ StunMessage msg;
+ StunMessage msg2;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress);
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ const StunAddressAttribute* addr =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ rtc::IPAddress test_address(kIPv4TestAddress1);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, kTestMessagePort3,
+ test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv6AddressAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ rtc::IPAddress test_address(kIPv6TestAddress1);
+
+ const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, kTestMessagePort2,
+ test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithInvalidAddressAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ rtc::IPAddress test_address(kIPv6TestAddress1);
+
+ const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, kTestMessagePort2,
+ test_address);
+}
+
+TEST_F(StunTest, ReadMessageWithIPv6XorAddressAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress);
+
+ rtc::IPAddress test_address(kIPv6TestAddress1);
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+ const StunAddressAttribute* addr =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, kTestMessagePort1,
+ test_address);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN request.
+TEST_F(StunTest, ReadRfc5769RequestMessage) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kRfc5769SampleRequest);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+ kStunTransactionIdLength);
+
+ const StunByteStringAttribute* software =
+ msg.GetByteString(STUN_ATTR_SOFTWARE);
+ ASSERT_TRUE(software != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgClientSoftware, software->string_view());
+
+ const StunByteStringAttribute* username =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(username != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgUsername, username->string_view());
+
+ // Actual M-I value checked in a later test.
+ ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+
+ // Fingerprint checked in a later test, but double-check the value here.
+ const StunUInt32Attribute* fingerprint = msg.GetUInt32(STUN_ATTR_FINGERPRINT);
+ ASSERT_TRUE(fingerprint != NULL);
+ EXPECT_EQ(0xe57a3bcf, fingerprint->value());
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response.
+TEST_F(StunTest, ReadRfc5769ResponseMessage) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kRfc5769SampleResponse);
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+ kStunTransactionIdLength);
+
+ const StunByteStringAttribute* software =
+ msg.GetByteString(STUN_ATTR_SOFTWARE);
+ ASSERT_TRUE(software != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->string_view());
+
+ const StunAddressAttribute* mapped_address =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ ASSERT_TRUE(mapped_address != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgMappedAddress, mapped_address->GetAddress());
+
+ // Actual M-I and fingerprint checked in later tests.
+ ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+ ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response for IPv6.
+TEST_F(StunTest, ReadRfc5769ResponseMessageIPv6) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kRfc5769SampleResponseIPv6);
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId,
+ kStunTransactionIdLength);
+
+ const StunByteStringAttribute* software =
+ msg.GetByteString(STUN_ATTR_SOFTWARE);
+ ASSERT_TRUE(software != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->string_view());
+
+ const StunAddressAttribute* mapped_address =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ ASSERT_TRUE(mapped_address != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgIPv6MappedAddress, mapped_address->GetAddress());
+
+ // Actual M-I and fingerprint checked in later tests.
+ ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+ ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL);
+}
+
+// Read the RFC5389 fields from the RFC5769 sample STUN response with auth.
+TEST_F(StunTest, ReadRfc5769RequestMessageLongTermAuth) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kRfc5769SampleRequestLongTermAuth);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kRfc5769SampleMsgWithAuthTransactionId,
+ kStunTransactionIdLength);
+
+ const StunByteStringAttribute* username =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(username != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgWithAuthUsername, username->string_view());
+
+ const StunByteStringAttribute* nonce = msg.GetByteString(STUN_ATTR_NONCE);
+ ASSERT_TRUE(nonce != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgWithAuthNonce, nonce->string_view());
+
+ const StunByteStringAttribute* realm = msg.GetByteString(STUN_ATTR_REALM);
+ ASSERT_TRUE(realm != NULL);
+ EXPECT_EQ(kRfc5769SampleMsgWithAuthRealm, realm->string_view());
+
+ // No fingerprint, actual M-I checked in later tests.
+ ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL);
+ ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) == NULL);
+}
+
+// The RFC3489 packet in this test is the same as
+// kStunMessageWithIPv4MappedAddress, but with a different value where the
+// magic cookie was.
+TEST_F(StunTest, ReadLegacyMessage) {
+ unsigned char rfc3489_packet[sizeof(kStunMessageWithIPv4MappedAddress)];
+ memcpy(rfc3489_packet, kStunMessageWithIPv4MappedAddress,
+ sizeof(kStunMessageWithIPv4MappedAddress));
+ // Overwrite the magic cookie here.
+ memcpy(&rfc3489_packet[4], "ABCD", 4);
+
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, rfc3489_packet);
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, &rfc3489_packet[4], kStunTransactionIdLength + 4);
+
+ const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::IPAddress test_address(kIPv4TestAddress1);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, kTestMessagePort4,
+ test_address);
+}
+
+TEST_F(StunTest, SetIPv6XorAddressAttributeOwner) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress);
+
+ rtc::IPAddress test_address(kIPv6TestAddress1);
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+ const StunAddressAttribute* addr =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, kTestMessagePort1,
+ test_address);
+
+ // Owner with a different transaction ID.
+ StunMessage msg2(STUN_INVALID_MESSAGE_TYPE, "ABCDABCDABCD");
+ StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL);
+ addr2.SetIP(addr->ipaddr());
+ addr2.SetPort(addr->port());
+ addr2.SetOwner(&msg2);
+ // The internal IP address shouldn't change.
+ ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+
+ rtc::ByteBufferWriter correct_buf;
+ rtc::ByteBufferWriter wrong_buf;
+ EXPECT_TRUE(addr->Write(&correct_buf));
+ EXPECT_TRUE(addr2.Write(&wrong_buf));
+ // But when written out, the buffers should look different.
+ ASSERT_NE(0,
+ memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
+ // And when reading a known good value, the address should be wrong.
+ rtc::ByteBufferReader read_buf(correct_buf);
+ addr2.Read(&read_buf);
+ ASSERT_NE(addr->ipaddr(), addr2.ipaddr());
+ addr2.SetIP(addr->ipaddr());
+ addr2.SetPort(addr->port());
+ // Try writing with no owner at all, should fail and write nothing.
+ addr2.SetOwner(NULL);
+ ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+ wrong_buf.Clear();
+ EXPECT_FALSE(addr2.Write(&wrong_buf));
+ ASSERT_EQ(0U, wrong_buf.Length());
+}
+
+TEST_F(StunTest, SetIPv4XorAddressAttributeOwner) {
+ // Unlike the IPv6XorAddressAttributeOwner test, IPv4 XOR address attributes
+ // should _not_ be affected by a change in owner. IPv4 XOR address uses the
+ // magic cookie value which is fixed.
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress);
+
+ rtc::IPAddress test_address(kIPv4TestAddress1);
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ const StunAddressAttribute* addr =
+ msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, kTestMessagePort3,
+ test_address);
+
+ // Owner with a different transaction ID.
+ StunMessage msg2(STUN_INVALID_MESSAGE_TYPE, "ABCDABCDABCD");
+ StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL);
+ addr2.SetIP(addr->ipaddr());
+ addr2.SetPort(addr->port());
+ addr2.SetOwner(&msg2);
+ // The internal IP address shouldn't change.
+ ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+
+ rtc::ByteBufferWriter correct_buf;
+ rtc::ByteBufferWriter wrong_buf;
+ EXPECT_TRUE(addr->Write(&correct_buf));
+ EXPECT_TRUE(addr2.Write(&wrong_buf));
+ // The same address data should be written.
+ ASSERT_EQ(0,
+ memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
+ // And an attribute should be able to un-XOR an address belonging to a message
+ // with a different transaction ID.
+ rtc::ByteBufferReader read_buf(correct_buf);
+ EXPECT_TRUE(addr2.Read(&read_buf));
+ ASSERT_EQ(addr->ipaddr(), addr2.ipaddr());
+
+ // However, no owner is still an error, should fail and write nothing.
+ addr2.SetOwner(NULL);
+ ASSERT_EQ(addr2.ipaddr(), addr->ipaddr());
+ wrong_buf.Clear();
+ EXPECT_FALSE(addr2.Write(&wrong_buf));
+}
+
+TEST_F(StunTest, CreateIPv6AddressAttribute) {
+ rtc::IPAddress test_ip(kIPv6TestAddress2);
+
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+ addr->SetAddress(test_addr);
+
+ CheckStunAddressAttribute(addr.get(), STUN_ADDRESS_IPV6, kTestMessagePort2,
+ test_ip);
+}
+
+TEST_F(StunTest, CreateIPv4AddressAttribute) {
+ struct in_addr test_in_addr;
+ test_in_addr.s_addr = 0xBEB0B0BE;
+ rtc::IPAddress test_ip(test_in_addr);
+
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+ addr->SetAddress(test_addr);
+
+ CheckStunAddressAttribute(addr.get(), STUN_ADDRESS_IPV4, kTestMessagePort2,
+ test_ip);
+}
+
+// Test that we don't care what order we set the parts of an address
+TEST_F(StunTest, CreateAddressInArbitraryOrder) {
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ // Port first
+ addr->SetPort(kTestMessagePort1);
+ addr->SetIP(rtc::IPAddress(kIPv4TestAddress1));
+ ASSERT_EQ(kTestMessagePort1, addr->port());
+ ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr->ipaddr());
+
+ auto addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ // IP first
+ addr2->SetIP(rtc::IPAddress(kIPv4TestAddress1));
+ addr2->SetPort(kTestMessagePort2);
+ ASSERT_EQ(kTestMessagePort2, addr2->port());
+ ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr2->ipaddr());
+}
+
+TEST_F(StunTest, WriteMessageWithIPv6AddressAttribute) {
+ size_t size = sizeof(kStunMessageWithIPv6MappedAddress);
+
+ rtc::IPAddress test_ip(kIPv6TestAddress1);
+
+ StunMessage msg(
+ STUN_BINDING_REQUEST,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+ addr->SetAddress(test_addr);
+ msg.AddAttribute(std::move(addr));
+
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6MappedAddress));
+ int len1 = static_cast<int>(out.Length());
+ rtc::ByteBufferReader read_buf(out);
+ std::string bytes;
+ read_buf.ReadString(&bytes, len1);
+ ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv6MappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) {
+ size_t size = sizeof(kStunMessageWithIPv4MappedAddress);
+
+ rtc::IPAddress test_ip(kIPv4TestAddress1);
+
+ StunMessage msg(
+ STUN_BINDING_RESPONSE,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort4);
+ addr->SetAddress(test_addr);
+ msg.AddAttribute(std::move(addr));
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4MappedAddress));
+ int len1 = static_cast<int>(out.Length());
+ rtc::ByteBufferReader read_buf(out);
+ std::string bytes;
+ read_buf.ReadString(&bytes, len1);
+ ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv4MappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) {
+ size_t size = sizeof(kStunMessageWithIPv6XorMappedAddress);
+
+ rtc::IPAddress test_ip(kIPv6TestAddress1);
+
+ StunMessage msg(
+ STUN_BINDING_RESPONSE,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId2),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+
+ auto addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort1);
+ addr->SetAddress(test_addr);
+ msg.AddAttribute(std::move(addr));
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6XorMappedAddress));
+ int len1 = static_cast<int>(out.Length());
+ rtc::ByteBufferReader read_buf(out);
+ std::string bytes;
+ read_buf.ReadString(&bytes, len1);
+ ASSERT_EQ(0,
+ memcmp(bytes.c_str(), kStunMessageWithIPv6XorMappedAddress, len1));
+}
+
+TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) {
+ size_t size = sizeof(kStunMessageWithIPv4XorMappedAddress);
+
+ rtc::IPAddress test_ip(kIPv4TestAddress1);
+
+ StunMessage msg(
+ STUN_BINDING_RESPONSE,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+
+ auto addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort3);
+ addr->SetAddress(test_addr);
+ msg.AddAttribute(std::move(addr));
+
+ CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4XorMappedAddress));
+ int len1 = static_cast<int>(out.Length());
+ rtc::ByteBufferReader read_buf(out);
+ std::string bytes;
+ read_buf.ReadString(&bytes, len1);
+ ASSERT_EQ(0,
+ memcmp(bytes.c_str(), kStunMessageWithIPv4XorMappedAddress, len1));
+}
+
+TEST_F(StunTest, ReadByteStringAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithByteStringAttribute);
+
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+ const StunByteStringAttribute* username =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(username != NULL);
+ EXPECT_EQ(kTestUserName1, username->string_view());
+}
+
+TEST_F(StunTest, ReadPaddedByteStringAttribute) {
+ StunMessage msg;
+ size_t size =
+ ReadStunMessage(&msg, kStunMessageWithPaddedByteStringAttribute);
+ ASSERT_NE(0U, size);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+ const StunByteStringAttribute* username =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(username != NULL);
+ EXPECT_EQ(kTestUserName2, username->string_view());
+}
+
+TEST_F(StunTest, ReadErrorCodeAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithErrorAttribute);
+
+ CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, size);
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+ const StunErrorCodeAttribute* errorcode = msg.GetErrorCode();
+ ASSERT_TRUE(errorcode != NULL);
+ EXPECT_EQ(kTestErrorClass, errorcode->eclass());
+ EXPECT_EQ(kTestErrorNumber, errorcode->number());
+ EXPECT_EQ(kTestErrorReason, errorcode->reason());
+ EXPECT_EQ(kTestErrorCode, errorcode->code());
+ EXPECT_EQ(kTestErrorCode, msg.GetErrorCodeValue());
+}
+
+// Test that GetErrorCodeValue returns STUN_ERROR_GLOBAL_FAILURE if the message
+// in question doesn't have an error code attribute, rather than crashing.
+TEST_F(StunTest, GetErrorCodeValueWithNoErrorAttribute) {
+ StunMessage msg;
+ ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress);
+ EXPECT_EQ(STUN_ERROR_GLOBAL_FAILURE, msg.GetErrorCodeValue());
+}
+
+TEST_F(StunTest, ReadMessageWithAUInt16ListAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithUInt16ListAttribute);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+ const StunUInt16ListAttribute* types = msg.GetUnknownAttributes();
+ ASSERT_TRUE(types != NULL);
+ EXPECT_EQ(3U, types->Size());
+ EXPECT_EQ(0x1U, types->GetType(0));
+ EXPECT_EQ(0x1000U, types->GetType(1));
+ EXPECT_EQ(0xAB0CU, types->GetType(2));
+}
+
+TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) {
+ StunMessage msg;
+ size_t size = ReadStunMessage(&msg, kStunMessageWithUnknownAttribute);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, size);
+
+ // Parsing should have succeeded and there should be a USERNAME attribute
+ const StunByteStringAttribute* username =
+ msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(username != NULL);
+ EXPECT_EQ(kTestUserName2, username->string_view());
+}
+
+TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) {
+ size_t size = sizeof(kStunMessageWithErrorAttribute);
+
+ StunMessage msg(
+ STUN_BINDING_ERROR_RESPONSE,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId1),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength);
+ auto errorcode = StunAttribute::CreateErrorCode();
+ errorcode->SetCode(kTestErrorCode);
+ errorcode->SetReason(kTestErrorReason);
+ msg.AddAttribute(std::move(errorcode));
+ CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(size, out.Length());
+ // No padding.
+ ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithErrorAttribute, size));
+}
+
+TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) {
+ size_t size = sizeof(kStunMessageWithUInt16ListAttribute);
+
+ StunMessage msg(
+ STUN_BINDING_REQUEST,
+ std::string(reinterpret_cast<const char*>(kTestTransactionId2),
+ kStunTransactionIdLength));
+ CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength);
+ auto list = StunAttribute::CreateUnknownAttributes();
+ list->AddType(0x1U);
+ list->AddType(0x1000U);
+ list->AddType(0xAB0CU);
+ msg.AddAttribute(std::move(list));
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(size, out.Length());
+ // Check everything up to the padding.
+ ASSERT_EQ(0,
+ memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2));
+}
+
+// Test that we fail to read messages with invalid lengths.
+void CheckFailureToRead(const unsigned char* testcase, size_t length) {
+ StunMessage msg;
+ const char* input = reinterpret_cast<const char*>(testcase);
+ rtc::ByteBufferReader buf(input, length);
+ ASSERT_FALSE(msg.Read(&buf));
+}
+
+TEST_F(StunTest, FailToReadInvalidMessages) {
+ CheckFailureToRead(kStunMessageWithZeroLength,
+ kRealLengthOfInvalidLengthTestCases);
+ CheckFailureToRead(kStunMessageWithSmallLength,
+ kRealLengthOfInvalidLengthTestCases);
+ CheckFailureToRead(kStunMessageWithExcessLength,
+ kRealLengthOfInvalidLengthTestCases);
+}
+
+// Test that we properly fail to read a non-STUN message.
+TEST_F(StunTest, FailToReadRtcpPacket) {
+ CheckFailureToRead(kRtcpPacket, sizeof(kRtcpPacket));
+}
+
+// Check our STUN message validation code against the RFC5769 test messages.
+TEST_F(StunTest, ValidateMessageIntegrity) {
+ // Try the messages from RFC 5769.
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleRequest),
+ sizeof(kRfc5769SampleRequest), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleRequest),
+ sizeof(kRfc5769SampleRequest), "InvalidPassword"));
+
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleResponse),
+ sizeof(kRfc5769SampleResponse), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleResponse),
+ sizeof(kRfc5769SampleResponse), "InvalidPassword"));
+
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+ sizeof(kRfc5769SampleResponseIPv6), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+ sizeof(kRfc5769SampleResponseIPv6), "InvalidPassword"));
+
+ // We first need to compute the key for the long-term authentication HMAC.
+ std::string key;
+ ComputeStunCredentialHash(kRfc5769SampleMsgWithAuthUsername,
+ kRfc5769SampleMsgWithAuthRealm,
+ kRfc5769SampleMsgWithAuthPassword, &key);
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth),
+ sizeof(kRfc5769SampleRequestLongTermAuth), key));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth),
+ sizeof(kRfc5769SampleRequestLongTermAuth), "InvalidPassword"));
+
+ // Try some edge cases.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+ sizeof(kStunMessageWithZeroLength), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+ sizeof(kStunMessageWithExcessLength), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+ sizeof(kStunMessageWithSmallLength), kRfc5769SampleMsgPassword));
+
+ // Again, but with the lengths matching what is claimed in the headers.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithZeroLength[2]),
+ kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithExcessLength[2]),
+ kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithSmallLength[2]),
+ kRfc5769SampleMsgPassword));
+
+ // Check that a too-short HMAC doesn't cause buffer overflow.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithBadHmacAtEnd),
+ sizeof(kStunMessageWithBadHmacAtEnd), kRfc5769SampleMsgPassword));
+
+ // Test that munging a single bit anywhere in the message causes the
+ // message-integrity check to fail, unless it is after the M-I attribute.
+ char buf[sizeof(kRfc5769SampleRequest)];
+ memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest));
+ for (size_t i = 0; i < sizeof(buf); ++i) {
+ buf[i] ^= 0x01;
+ if (i > 0)
+ buf[i - 1] ^= 0x01;
+ EXPECT_EQ(i >= sizeof(buf) - 8,
+ StunMessage::ValidateMessageIntegrityForTesting(
+ buf, sizeof(buf), kRfc5769SampleMsgPassword));
+ }
+}
+
+// Validate that we generate correct MESSAGE-INTEGRITY attributes.
+// Note the use of IceMessage instead of StunMessage; this is necessary because
+// the RFC5769 test messages used include attributes not found in basic STUN.
+TEST_F(StunTest, AddMessageIntegrity) {
+ IceMessage msg;
+ rtc::ByteBufferReader buf(
+ reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI),
+ sizeof(kRfc5769SampleRequestWithoutMI));
+ EXPECT_TRUE(msg.Read(&buf));
+ EXPECT_TRUE(msg.AddMessageIntegrity(kRfc5769SampleMsgPassword));
+ const StunByteStringAttribute* mi_attr =
+ msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+ EXPECT_EQ(20U, mi_attr->length());
+ EXPECT_EQ(
+ 0, memcmp(mi_attr->bytes(), kCalculatedHmac1, sizeof(kCalculatedHmac1)));
+
+ rtc::ByteBufferWriter buf1;
+ EXPECT_TRUE(msg.Write(&buf1));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(),
+ kRfc5769SampleMsgPassword));
+
+ IceMessage msg2;
+ rtc::ByteBufferReader buf2(
+ reinterpret_cast<const char*>(kRfc5769SampleResponseWithoutMI),
+ sizeof(kRfc5769SampleResponseWithoutMI));
+ EXPECT_TRUE(msg2.Read(&buf2));
+ EXPECT_TRUE(msg2.AddMessageIntegrity(kRfc5769SampleMsgPassword));
+ const StunByteStringAttribute* mi_attr2 =
+ msg2.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
+ EXPECT_EQ(20U, mi_attr2->length());
+ EXPECT_EQ(
+ 0, memcmp(mi_attr2->bytes(), kCalculatedHmac2, sizeof(kCalculatedHmac2)));
+
+ rtc::ByteBufferWriter buf3;
+ EXPECT_TRUE(msg2.Write(&buf3));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(buf3.Data()), buf3.Length(),
+ kRfc5769SampleMsgPassword));
+}
+
+// Check our STUN message validation code against the RFC5769 test messages.
+TEST_F(StunTest, ValidateMessageIntegrity32) {
+ // Try the messages from RFC 5769.
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kSampleRequestMI32),
+ sizeof(kSampleRequestMI32), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kSampleRequestMI32),
+ sizeof(kSampleRequestMI32), "InvalidPassword"));
+
+ // Try some edge cases.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+ sizeof(kStunMessageWithZeroLength), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+ sizeof(kStunMessageWithExcessLength), kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+ sizeof(kStunMessageWithSmallLength), kRfc5769SampleMsgPassword));
+
+ // Again, but with the lengths matching what is claimed in the headers.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithZeroLength[2]),
+ kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithExcessLength[2]),
+ kRfc5769SampleMsgPassword));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+ kStunHeaderSize + rtc::GetBE16(&kStunMessageWithSmallLength[2]),
+ kRfc5769SampleMsgPassword));
+
+ // Check that a too-short HMAC doesn't cause buffer overflow.
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(kStunMessageWithBadHmacAtEnd),
+ sizeof(kStunMessageWithBadHmacAtEnd), kRfc5769SampleMsgPassword));
+
+ // Test that munging a single bit anywhere in the message causes the
+ // message-integrity check to fail, unless it is after the M-I attribute.
+ char buf[sizeof(kSampleRequestMI32)];
+ memcpy(buf, kSampleRequestMI32, sizeof(kSampleRequestMI32));
+ for (size_t i = 0; i < sizeof(buf); ++i) {
+ buf[i] ^= 0x01;
+ if (i > 0)
+ buf[i - 1] ^= 0x01;
+ EXPECT_EQ(i >= sizeof(buf) - 8,
+ StunMessage::ValidateMessageIntegrity32ForTesting(
+ buf, sizeof(buf), kRfc5769SampleMsgPassword));
+ }
+}
+
+// Validate that we generate correct MESSAGE-INTEGRITY-32 attributes.
+TEST_F(StunTest, AddMessageIntegrity32) {
+ IceMessage msg;
+ rtc::ByteBufferReader buf(
+ reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI),
+ sizeof(kRfc5769SampleRequestWithoutMI));
+ EXPECT_TRUE(msg.Read(&buf));
+ EXPECT_TRUE(msg.AddMessageIntegrity32(kRfc5769SampleMsgPassword));
+ const StunByteStringAttribute* mi_attr =
+ msg.GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32);
+ EXPECT_EQ(4U, mi_attr->length());
+ EXPECT_EQ(0, memcmp(mi_attr->bytes(), kCalculatedHmac1_32,
+ sizeof(kCalculatedHmac1_32)));
+
+ rtc::ByteBufferWriter buf1;
+ EXPECT_TRUE(msg.Write(&buf1));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(),
+ kRfc5769SampleMsgPassword));
+
+ IceMessage msg2;
+ rtc::ByteBufferReader buf2(
+ reinterpret_cast<const char*>(kRfc5769SampleResponseWithoutMI),
+ sizeof(kRfc5769SampleResponseWithoutMI));
+ EXPECT_TRUE(msg2.Read(&buf2));
+ EXPECT_TRUE(msg2.AddMessageIntegrity32(kRfc5769SampleMsgPassword));
+ const StunByteStringAttribute* mi_attr2 =
+ msg2.GetByteString(STUN_ATTR_GOOG_MESSAGE_INTEGRITY_32);
+ EXPECT_EQ(4U, mi_attr2->length());
+ EXPECT_EQ(0, memcmp(mi_attr2->bytes(), kCalculatedHmac2_32,
+ sizeof(kCalculatedHmac2_32)));
+
+ rtc::ByteBufferWriter buf3;
+ EXPECT_TRUE(msg2.Write(&buf3));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(buf3.Data()), buf3.Length(),
+ kRfc5769SampleMsgPassword));
+}
+
+// Validate that the message validates if both MESSAGE-INTEGRITY-32 and
+// MESSAGE-INTEGRITY are present in the message.
+// This is not expected to be used, but is not forbidden.
+TEST_F(StunTest, AddMessageIntegrity32AndMessageIntegrity) {
+ IceMessage msg;
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("keso", sizeof("keso"));
+ msg.AddAttribute(std::move(attr));
+ msg.AddMessageIntegrity32("password1");
+ msg.AddMessageIntegrity("password2");
+
+ rtc::ByteBufferWriter buf1;
+ EXPECT_TRUE(msg.Write(&buf1));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(), "password1"));
+ EXPECT_TRUE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(), "password2"));
+
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrity32ForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(), "password2"));
+ EXPECT_FALSE(StunMessage::ValidateMessageIntegrityForTesting(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length(), "password1"));
+}
+
+// Check our STUN message validation code against the RFC5769 test messages.
+TEST_F(StunTest, ValidateFingerprint) {
+ EXPECT_TRUE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kRfc5769SampleRequest),
+ sizeof(kRfc5769SampleRequest)));
+ EXPECT_TRUE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kRfc5769SampleResponse),
+ sizeof(kRfc5769SampleResponse)));
+ EXPECT_TRUE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6),
+ sizeof(kRfc5769SampleResponseIPv6)));
+
+ EXPECT_FALSE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kStunMessageWithZeroLength),
+ sizeof(kStunMessageWithZeroLength)));
+ EXPECT_FALSE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kStunMessageWithExcessLength),
+ sizeof(kStunMessageWithExcessLength)));
+ EXPECT_FALSE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(kStunMessageWithSmallLength),
+ sizeof(kStunMessageWithSmallLength)));
+
+ // Test that munging a single bit anywhere in the message causes the
+ // fingerprint check to fail.
+ char buf[sizeof(kRfc5769SampleRequest)];
+ memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest));
+ for (size_t i = 0; i < sizeof(buf); ++i) {
+ buf[i] ^= 0x01;
+ if (i > 0)
+ buf[i - 1] ^= 0x01;
+ EXPECT_FALSE(StunMessage::ValidateFingerprint(buf, sizeof(buf)));
+ }
+ // Put them all back to normal and the check should pass again.
+ buf[sizeof(buf) - 1] ^= 0x01;
+ EXPECT_TRUE(StunMessage::ValidateFingerprint(buf, sizeof(buf)));
+}
+
+TEST_F(StunTest, AddFingerprint) {
+ IceMessage msg;
+ rtc::ByteBufferReader buf(
+ reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI),
+ sizeof(kRfc5769SampleRequestWithoutMI));
+ EXPECT_TRUE(msg.Read(&buf));
+ EXPECT_TRUE(msg.AddFingerprint());
+
+ rtc::ByteBufferWriter buf1;
+ EXPECT_TRUE(msg.Write(&buf1));
+ EXPECT_TRUE(StunMessage::ValidateFingerprint(
+ reinterpret_cast<const char*>(buf1.Data()), buf1.Length()));
+}
+
+// Sample "GTURN" relay message.
+// clang-format off
+// clang formatting doesn't respect inline comments.
+static const unsigned char kRelayMessage[] = {
+ 0x00, 0x01, 0x00, 88, // message header
+ 0x21, 0x12, 0xA4, 0x42, // magic cookie
+ '0', '1', '2', '3', // transaction id
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 0x00, 0x01, 0x00, 8, // mapped address
+ 0x00, 0x01, 0x00, 13,
+ 0x00, 0x00, 0x00, 17,
+ 0x00, 0x06, 0x00, 12, // username
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 0x00, 0x0d, 0x00, 4, // lifetime
+ 0x00, 0x00, 0x00, 11,
+ 0x00, 0x0f, 0x00, 4, // magic cookie
+ 0x72, 0xc6, 0x4b, 0xc6,
+ 0x00, 0x10, 0x00, 4, // bandwidth
+ 0x00, 0x00, 0x00, 6,
+ 0x00, 0x11, 0x00, 8, // destination address
+ 0x00, 0x01, 0x00, 13,
+ 0x00, 0x00, 0x00, 17,
+ 0x00, 0x12, 0x00, 8, // source address 2
+ 0x00, 0x01, 0x00, 13,
+ 0x00, 0x00, 0x00, 17,
+ 0x00, 0x13, 0x00, 7, // data
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 0 // DATA must be padded per rfc5766.
+};
+// clang-format on
+
+// Test that we can read the GTURN-specific fields.
+TEST_F(StunTest, ReadRelayMessage) {
+ RelayMessage msg;
+
+ const char* input = reinterpret_cast<const char*>(kRelayMessage);
+ size_t size = sizeof(kRelayMessage);
+ rtc::ByteBufferReader buf(input, size);
+ EXPECT_TRUE(msg.Read(&buf));
+
+ EXPECT_EQ(STUN_BINDING_REQUEST, msg.type());
+ EXPECT_EQ(size - 20, msg.length());
+ EXPECT_EQ("0123456789ab", msg.transaction_id());
+
+ RelayMessage msg2(STUN_BINDING_REQUEST, "0123456789ab");
+
+ in_addr legacy_in_addr;
+ legacy_in_addr.s_addr = htonl(17U);
+ rtc::IPAddress legacy_ip(legacy_in_addr);
+
+ const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS);
+ ASSERT_TRUE(addr != NULL);
+ EXPECT_EQ(1, addr->family());
+ EXPECT_EQ(13, addr->port());
+ EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+ auto addr2 = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ addr2->SetPort(13);
+ addr2->SetIP(legacy_ip);
+ msg2.AddAttribute(std::move(addr2));
+
+ const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME);
+ ASSERT_TRUE(bytes != NULL);
+ EXPECT_EQ(12U, bytes->length());
+ EXPECT_EQ("abcdefghijkl", bytes->string_view());
+
+ auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ bytes2->CopyBytes("abcdefghijkl");
+ msg2.AddAttribute(std::move(bytes2));
+
+ const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME);
+ ASSERT_TRUE(uval != NULL);
+ EXPECT_EQ(11U, uval->value());
+
+ auto uval2 = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
+ uval2->SetValue(11);
+ msg2.AddAttribute(std::move(uval2));
+
+ bytes = msg.GetByteString(STUN_ATTR_MAGIC_COOKIE);
+ ASSERT_TRUE(bytes != NULL);
+ EXPECT_EQ(4U, bytes->length());
+ EXPECT_EQ(0, memcmp(bytes->bytes(), TURN_MAGIC_COOKIE_VALUE,
+ sizeof(TURN_MAGIC_COOKIE_VALUE)));
+
+ bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+ bytes2->CopyBytes(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
+ sizeof(TURN_MAGIC_COOKIE_VALUE));
+ msg2.AddAttribute(std::move(bytes2));
+
+ uval = msg.GetUInt32(STUN_ATTR_BANDWIDTH);
+ ASSERT_TRUE(uval != NULL);
+ EXPECT_EQ(6U, uval->value());
+
+ uval2 = StunAttribute::CreateUInt32(STUN_ATTR_BANDWIDTH);
+ uval2->SetValue(6);
+ msg2.AddAttribute(std::move(uval2));
+
+ addr = msg.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ ASSERT_TRUE(addr != NULL);
+ EXPECT_EQ(1, addr->family());
+ EXPECT_EQ(13, addr->port());
+ EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+ addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
+ addr2->SetPort(13);
+ addr2->SetIP(legacy_ip);
+ msg2.AddAttribute(std::move(addr2));
+
+ addr = msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
+ ASSERT_TRUE(addr != NULL);
+ EXPECT_EQ(1, addr->family());
+ EXPECT_EQ(13, addr->port());
+ EXPECT_EQ(legacy_ip, addr->ipaddr());
+
+ addr2 = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
+ addr2->SetPort(13);
+ addr2->SetIP(legacy_ip);
+ msg2.AddAttribute(std::move(addr2));
+
+ bytes = msg.GetByteString(STUN_ATTR_DATA);
+ ASSERT_TRUE(bytes != NULL);
+ EXPECT_EQ(7U, bytes->length());
+ EXPECT_EQ("abcdefg", bytes->string_view());
+
+ bytes2 = StunAttribute::CreateByteString(STUN_ATTR_DATA);
+ bytes2->CopyBytes("abcdefg");
+ msg2.AddAttribute(std::move(bytes2));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ EXPECT_EQ(size, out.Length());
+ size_t len1 = out.Length();
+ rtc::ByteBufferReader read_buf(out);
+ std::string outstring;
+ read_buf.ReadString(&outstring, len1);
+ EXPECT_EQ(0, memcmp(outstring.c_str(), input, len1));
+
+ rtc::ByteBufferWriter out2;
+ EXPECT_TRUE(msg2.Write(&out2));
+ EXPECT_EQ(size, out2.Length());
+ size_t len2 = out2.Length();
+ rtc::ByteBufferReader read_buf2(out2);
+ std::string outstring2;
+ read_buf2.ReadString(&outstring2, len2);
+ EXPECT_EQ(0, memcmp(outstring2.c_str(), input, len2));
+}
+
+// Test that we can remove attribute from a message.
+TEST_F(StunTest, RemoveAttribute) {
+ StunMessage msg;
+
+ // Removing something that does exist should return nullptr.
+ EXPECT_EQ(msg.RemoveAttribute(STUN_ATTR_USERNAME), nullptr);
+
+ {
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("kes", sizeof("kes"));
+ msg.AddAttribute(std::move(attr));
+ }
+
+ size_t len = msg.length();
+ {
+ auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME);
+ ASSERT_NE(attr, nullptr);
+ EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME);
+ EXPECT_STREQ("kes",
+ static_cast<StunByteStringAttribute*>(attr.get())->bytes());
+ EXPECT_LT(msg.length(), len);
+ }
+
+ // Now add same attribute type twice.
+ {
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("kes", sizeof("kes"));
+ msg.AddAttribute(std::move(attr));
+ }
+
+ {
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("kenta", sizeof("kenta"));
+ msg.AddAttribute(std::move(attr));
+ }
+
+ // Remove should remove the last added occurrence.
+ {
+ auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME);
+ ASSERT_NE(attr, nullptr);
+ EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME);
+ EXPECT_STREQ("kenta",
+ static_cast<StunByteStringAttribute*>(attr.get())->bytes());
+ }
+
+ // Remove should remove the last added occurrence.
+ {
+ auto attr = msg.RemoveAttribute(STUN_ATTR_USERNAME);
+ ASSERT_NE(attr, nullptr);
+ EXPECT_EQ(attr->type(), STUN_ATTR_USERNAME);
+ EXPECT_STREQ("kes",
+ static_cast<StunByteStringAttribute*>(attr.get())->bytes());
+ }
+
+ // Removing something that does exist should return nullptr.
+ EXPECT_EQ(msg.RemoveAttribute(STUN_ATTR_USERNAME), nullptr);
+}
+
+// Test that we can remove attribute from a message.
+TEST_F(StunTest, ClearAttributes) {
+ StunMessage msg;
+
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("kes", sizeof("kes"));
+ msg.AddAttribute(std::move(attr));
+ size_t len = msg.length();
+
+ msg.ClearAttributes();
+ EXPECT_EQ(msg.length(), len - /* 3 + 1 byte padding + header */ 8);
+ EXPECT_EQ(nullptr, msg.GetByteString(STUN_ATTR_USERNAME));
+}
+
+// Test CopyStunAttribute
+TEST_F(StunTest, CopyAttribute) {
+ rtc::ByteBufferWriter buf;
+ rtc::ByteBufferWriter* buffer_ptrs[] = {&buf, nullptr};
+ // Test both with and without supplied ByteBufferWriter.
+ for (auto buffer_ptr : buffer_ptrs) {
+ { // Test StunByteStringAttribute.
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ attr->CopyBytes("kes", sizeof("kes"));
+
+ auto copy = CopyStunAttribute(*attr.get(), buffer_ptr);
+ ASSERT_EQ(copy->value_type(), STUN_VALUE_BYTE_STRING);
+ EXPECT_STREQ("kes",
+ static_cast<StunByteStringAttribute*>(copy.get())->bytes());
+ }
+
+ { // Test StunAddressAttribute.
+ rtc::IPAddress test_ip(kIPv6TestAddress2);
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+ addr->SetAddress(test_addr);
+ CheckStunAddressAttribute(addr.get(), STUN_ADDRESS_IPV6,
+ kTestMessagePort2, test_ip);
+
+ auto copy = CopyStunAttribute(*addr.get(), buffer_ptr);
+ ASSERT_EQ(copy->value_type(), STUN_VALUE_ADDRESS);
+ CheckStunAddressAttribute(static_cast<StunAddressAttribute*>(copy.get()),
+ STUN_ADDRESS_IPV6, kTestMessagePort2, test_ip);
+ }
+
+ { // Test StunAddressAttribute.
+ rtc::IPAddress test_ip(kIPv6TestAddress2);
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
+ rtc::SocketAddress test_addr(test_ip, kTestMessagePort2);
+ addr->SetAddress(test_addr);
+ CheckStunAddressAttribute(addr.get(), STUN_ADDRESS_IPV6,
+ kTestMessagePort2, test_ip);
+
+ auto copy = CopyStunAttribute(*addr.get(), buffer_ptr);
+ ASSERT_EQ(copy->value_type(), STUN_VALUE_ADDRESS);
+ CheckStunAddressAttribute(static_cast<StunAddressAttribute*>(copy.get()),
+ STUN_ADDRESS_IPV6, kTestMessagePort2, test_ip);
+ }
+ }
+}
+
+// Test Clone
+TEST_F(StunTest, Clone) {
+ IceMessage msg(0, "0123456789ab");
+ {
+ auto errorcode = StunAttribute::CreateErrorCode();
+ errorcode->SetCode(kTestErrorCode);
+ errorcode->SetReason(kTestErrorReason);
+ msg.AddAttribute(std::move(errorcode));
+ }
+ {
+ auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ bytes2->CopyBytes("abcdefghijkl");
+ msg.AddAttribute(std::move(bytes2));
+ }
+ {
+ auto uval2 = StunAttribute::CreateUInt32(STUN_ATTR_RETRANSMIT_COUNT);
+ uval2->SetValue(11);
+ msg.AddAttribute(std::move(uval2));
+ }
+ {
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ addr->SetIP(rtc::IPAddress(kIPv6TestAddress1));
+ addr->SetPort(kTestMessagePort1);
+ msg.AddAttribute(std::move(addr));
+ }
+ auto copy = msg.Clone();
+ ASSERT_NE(nullptr, copy.get());
+
+ rtc::ByteBufferWriter out1;
+ EXPECT_TRUE(msg.Write(&out1));
+ rtc::ByteBufferWriter out2;
+ EXPECT_TRUE(copy->Write(&out2));
+
+ ASSERT_EQ(out1.Length(), out2.Length());
+ EXPECT_EQ(0, memcmp(out1.Data(), out2.Data(), out1.Length()));
+}
+
+// Test EqualAttributes
+TEST_F(StunTest, EqualAttributes) {
+ IceMessage msg;
+ {
+ auto errorcode = StunAttribute::CreateErrorCode();
+ errorcode->SetCode(kTestErrorCode);
+ errorcode->SetReason(kTestErrorReason);
+ msg.AddAttribute(std::move(errorcode));
+ }
+ {
+ auto bytes2 = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ bytes2->CopyBytes("abcdefghijkl");
+ msg.AddAttribute(std::move(bytes2));
+ }
+ {
+ auto uval2 = StunAttribute::CreateUInt32(STUN_ATTR_RETRANSMIT_COUNT);
+ uval2->SetValue(11);
+ msg.AddAttribute(std::move(uval2));
+ }
+ {
+ auto addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+ addr->SetIP(rtc::IPAddress(kIPv6TestAddress1));
+ addr->SetPort(kTestMessagePort1);
+ msg.AddAttribute(std::move(addr));
+ }
+ auto copy = msg.Clone();
+ ASSERT_NE(nullptr, copy.get());
+
+ EXPECT_TRUE(copy->EqualAttributes(&msg, [](int type) { return true; }));
+
+ {
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
+ attr->CopyBytes("keso");
+ msg.AddAttribute(std::move(attr));
+ EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
+ EXPECT_TRUE(copy->EqualAttributes(
+ &msg, [](int type) { return type != STUN_ATTR_NONCE; }));
+ }
+
+ {
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
+ attr->CopyBytes("keso");
+ copy->AddAttribute(std::move(attr));
+ EXPECT_TRUE(copy->EqualAttributes(&msg, [](int type) { return true; }));
+ }
+ {
+ copy->RemoveAttribute(STUN_ATTR_NONCE);
+ auto attr = StunAttribute::CreateByteString(STUN_ATTR_NONCE);
+ attr->CopyBytes("kent");
+ copy->AddAttribute(std::move(attr));
+ EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
+ EXPECT_TRUE(copy->EqualAttributes(
+ &msg, [](int type) { return type != STUN_ATTR_NONCE; }));
+ }
+
+ {
+ msg.RemoveAttribute(STUN_ATTR_NONCE);
+ EXPECT_FALSE(copy->EqualAttributes(&msg, [](int type) { return true; }));
+ EXPECT_TRUE(copy->EqualAttributes(
+ &msg, [](int type) { return type != STUN_ATTR_NONCE; }));
+ }
+}
+
+TEST_F(StunTest, ReduceTransactionIdIsHostOrderIndependent) {
+ const std::string transaction_id = "abcdefghijkl";
+ StunMessage message(0, transaction_id);
+ uint32_t reduced_transaction_id = message.reduced_transaction_id();
+ EXPECT_EQ(reduced_transaction_id, 1835954016u);
+}
+
+TEST_F(StunTest, GoogMiscInfo) {
+ StunMessage msg(STUN_BINDING_REQUEST, "ABCDEFGHIJKL");
+ const size_t size =
+ /* msg header */ 20 +
+ /* attr header */ 4 +
+ /* 3 * 2 rounded to multiple of 4 */ 8;
+ auto list =
+ StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
+ list->AddTypeAtIndex(0, 0x1U);
+ list->AddTypeAtIndex(3, 0x1000U);
+ list->AddTypeAtIndex(2, 0xAB0CU);
+ msg.AddAttribute(std::move(list));
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20));
+
+ rtc::ByteBufferWriter out;
+ EXPECT_TRUE(msg.Write(&out));
+ ASSERT_EQ(size, out.Length());
+
+ size_t read_size = ReadStunMessageTestCase(
+ &msg, reinterpret_cast<const unsigned char*>(out.Data()), out.Length());
+ ASSERT_EQ(read_size + 20, size);
+ CheckStunHeader(msg, STUN_BINDING_REQUEST, read_size);
+ const StunUInt16ListAttribute* types =
+ msg.GetUInt16List(STUN_ATTR_GOOG_MISC_INFO);
+ ASSERT_TRUE(types != NULL);
+ EXPECT_EQ(4U, types->Size());
+ EXPECT_EQ(0x1U, types->GetType(0));
+ EXPECT_EQ(0x0U, types->GetType(1));
+ EXPECT_EQ(0x1000U, types->GetType(3));
+ EXPECT_EQ(0xAB0CU, types->GetType(2));
+}
+
+TEST_F(StunTest, IsStunMethod) {
+ int methods[] = {STUN_BINDING_REQUEST};
+ EXPECT_TRUE(StunMessage::IsStunMethod(
+ methods, reinterpret_cast<const char*>(kRfc5769SampleRequest),
+ sizeof(kRfc5769SampleRequest)));
+}
+
+TEST_F(StunTest, SizeRestrictionOnAttributes) {
+ StunMessage msg(STUN_BINDING_REQUEST, "ABCDEFGHIJKL");
+ auto long_username = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ std::string long_string(509, 'x');
+ long_username->CopyBytes(long_string.c_str(), long_string.size());
+ msg.AddAttribute(std::move(long_username));
+ rtc::ByteBufferWriter out;
+ ASSERT_FALSE(msg.Write(&out));
+}
+
+TEST_F(StunTest, ValidateMessageIntegrityWithParser) {
+ webrtc::metrics::Reset(); // Ensure counters start from zero.
+ // Try the messages from RFC 5769.
+ StunMessage message;
+ rtc::ByteBufferReader reader(
+ reinterpret_cast<const char*>(kRfc5769SampleRequest),
+ sizeof(kRfc5769SampleRequest));
+ EXPECT_TRUE(message.Read(&reader));
+ EXPECT_EQ(message.ValidateMessageIntegrity(kRfc5769SampleMsgPassword),
+ StunMessage::IntegrityStatus::kIntegrityOk);
+ EXPECT_EQ(webrtc::metrics::NumEvents(
+ "WebRTC.Stun.Integrity.Request",
+ static_cast<int>(StunMessage::IntegrityStatus::kIntegrityOk)),
+ 1);
+ EXPECT_EQ(message.RevalidateMessageIntegrity("Invalid password"),
+ StunMessage::IntegrityStatus::kIntegrityBad);
+ EXPECT_EQ(webrtc::metrics::NumEvents(
+ "WebRTC.Stun.Integrity.Request",
+ static_cast<int>(StunMessage::IntegrityStatus::kIntegrityBad)),
+ 1);
+ EXPECT_EQ(webrtc::metrics::NumSamples("WebRTC.Stun.Integrity.Request"), 2);
+}
+
+} // namespace cricket
diff --git a/third_party/libwebrtc/api/transport/test/create_feedback_generator.cc b/third_party/libwebrtc/api/transport/test/create_feedback_generator.cc
new file mode 100644
index 0000000000..7c83823ce4
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/test/create_feedback_generator.cc
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/transport/test/create_feedback_generator.h"
+
+#include <memory>
+
+#include "test/network/feedback_generator.h"
+
+namespace webrtc {
+
+std::unique_ptr<FeedbackGenerator> CreateFeedbackGenerator(
+ FeedbackGenerator::Config confg) {
+ return std::make_unique<FeedbackGeneratorImpl>(confg);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/api/transport/test/create_feedback_generator.h b/third_party/libwebrtc/api/transport/test/create_feedback_generator.h
new file mode 100644
index 0000000000..a1a2226496
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/test/create_feedback_generator.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_
+#define API_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_
+
+#include <memory>
+
+#include "api/transport/test/feedback_generator_interface.h"
+
+namespace webrtc {
+std::unique_ptr<FeedbackGenerator> CreateFeedbackGenerator(
+ FeedbackGenerator::Config confg);
+} // namespace webrtc
+#endif // API_TRANSPORT_TEST_CREATE_FEEDBACK_GENERATOR_H_
diff --git a/third_party/libwebrtc/api/transport/test/feedback_generator_interface.h b/third_party/libwebrtc/api/transport/test/feedback_generator_interface.h
new file mode 100644
index 0000000000..6e5118cbf4
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/test/feedback_generator_interface.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_
+#define API_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_
+
+#include <vector>
+
+#include "api/test/simulated_network.h"
+#include "api/transport/network_types.h"
+
+namespace webrtc {
+class FeedbackGenerator {
+ public:
+ struct Config {
+ BuiltInNetworkBehaviorConfig send_link;
+ BuiltInNetworkBehaviorConfig return_link;
+ TimeDelta feedback_interval = TimeDelta::Millis(50);
+ DataSize feedback_packet_size = DataSize::Bytes(20);
+ };
+ virtual ~FeedbackGenerator() = default;
+ virtual Timestamp Now() = 0;
+ virtual void Sleep(TimeDelta duration) = 0;
+ virtual void SendPacket(size_t size) = 0;
+ virtual std::vector<TransportPacketsFeedback> PopFeedback() = 0;
+ virtual void SetSendConfig(BuiltInNetworkBehaviorConfig config) = 0;
+ virtual void SetReturnConfig(BuiltInNetworkBehaviorConfig config) = 0;
+ virtual void SetSendLinkCapacity(DataRate capacity) = 0;
+};
+} // namespace webrtc
+#endif // API_TRANSPORT_TEST_FEEDBACK_GENERATOR_INTERFACE_H_
diff --git a/third_party/libwebrtc/api/transport/test/mock_network_control.h b/third_party/libwebrtc/api/transport/test/mock_network_control.h
new file mode 100644
index 0000000000..f613004fb7
--- /dev/null
+++ b/third_party/libwebrtc/api/transport/test/mock_network_control.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_
+#define API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_
+
+#include "api/transport/network_control.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockNetworkStateEstimator : public NetworkStateEstimator {
+ public:
+ MOCK_METHOD(absl::optional<NetworkStateEstimate>,
+ GetCurrentEstimate,
+ (),
+ (override));
+ MOCK_METHOD(void,
+ OnTransportPacketsFeedback,
+ (const TransportPacketsFeedback&),
+ (override));
+ MOCK_METHOD(void, OnReceivedPacket, (const PacketResult&), (override));
+ MOCK_METHOD(void, OnRouteChange, (const NetworkRouteChange&), (override));
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_