diff options
Diffstat (limited to 'third_party/libwebrtc/api/transport')
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_ |